今天在和小伙伴codereview发现,平时使用idea自动生成变量名时一直默认在变量前加final,起初还以为这样会有什么性能的提升,所以idea默认加上。然后发现小伙伴们基本上都不怎么这样用。对于局部变量要不要加final产生了很大的争议。下面通过实操为大家揭开面纱。
网上的观点 网上对这个的争议也很大,但大都偏向:final修饰局部变量可以提高访问速度。
实操 考虑到fianl修饰的变量类型不同可能产生的效果不同,我们分别对基本类型和包装类型的局部变量进行验证
基本类型
1 2 3 4 5 6 7 8 9 10 11 12 13 public int intFinalSum () { final int a=34 ; final int b=30 ; return a+b; } public int intSum () { int a=34 ; int b=30 ; return a+b; }
包装类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public User getFinalUser () { final User user = new User(); user.setAge(12 ); user.setName("测试" ); user.setId(new Random().nextInt()); return user; } public User getUser () { User user = new User(); user.setAge(12 ); user.setName("测试" ); user.setId(new Random().nextInt()); return user; }
下面对上述代买进行测试。
方式一:采用JMH进行耗时测试: 模拟用户请求,预热5次,总量10,统计单位微妙,分别对包装类型和基本类型进行测试。
1 2 3 4 5 Benchmark Mode Samples Mean Mean error Units c.l.j.t.BasicType.getFinalUser avgt 10 0.081 0.024 us/op c.l.j.t.BasicType.getUser avgt 10 0.068 0.004 us/op c.l.j.t.BasicType.intFinalSum avgt 10 0.001 0.000 us/op c.l.j.t.BasicType.intSum avgt 10 0.001 0.000 us/op
从上面结果来看消耗时间来看,基本类型耗时一致,包装类型差异不大。
考虑到测试的数据量有限,耗时暂作为参考。
方式二:编译后的字节码对比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public com.xfyh.jmhtest.test.FinalTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public int intFinalSum(); Code: 0: bipush 34 2: istore_1 3: bipush 30 5: istore_2 6: bipush 64 8: ireturn public int intSum(); Code: 0: bipush 34 2: istore_1 3: bipush 30 5: istore_2 6: iload_1 7: iload_2 8: iadd 9: ireturn public com.xfyh.jmhtest.model.User getFinalUser(); Code: 0: new #2 // class com/xfyh/jmhtest/model/User 3: dup 4: invokespecial #3 // Method com/xfyh/jmhtest/model/User."<init>":()V 7: astore_1 8: aload_1 9: bipush 12 11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 14: invokevirtual #5 // Method com/xfyh/jmhtest/model/User.setAge:(Ljava/lang/Integer;)V 17: aload_1 18: ldc #6 // String 测试 20: invokevirtual #7 // Method com/xfyh/jmhtest/model/User.setName:(Ljava/lang/String;)V 23: aload_1 24: new #8 // class java/util/Random 27: dup 28: invokespecial #9 // Method java/util/Random."<init>":()V 31: invokevirtual #10 // Method java/util/Random.nextInt:()I 34: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 37: invokevirtual #11 // Method com/xfyh/jmhtest/model/User.setId:(Ljava/lang/Integer;)V 40: aload_1 41: areturn public com.xfyh.jmhtest.model.User getUser(); Code: 0: new #2 // class com/xfyh/jmhtest/model/User 3: dup 4: invokespecial #3 // Method com/xfyh/jmhtest/model/User."<init>":()V 7: astore_1 8: aload_1 9: bipush 12 11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 14: invokevirtual #5 // Method com/xfyh/jmhtest/model/User.setAge:(Ljava/lang/Integer;)V 17: aload_1 18: ldc #6 // String 测试 20: invokevirtual #7 // Method com/xfyh/jmhtest/model/User.setName:(Ljava/lang/String;)V 23: aload_1 24: new #8 // class java/util/Random 27: dup 28: invokespecial #9 // Method java/util/Random."<init>":()V 31: invokevirtual #10 // Method java/util/Random.nextInt:()I 34: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 37: invokevirtual #11 // Method com/xfyh/jmhtest/model/User.setId:(Ljava/lang/Integer;)V 40: aload_1 41: areturn
从字节码上面分析,对于基本类型,final修饰的命令简短,所以判断final修饰的要快一些,包装类型字节码指令完全一样,所以加不加都一样。没差异。
结论 通过上面两个实验,我们可以看出,局部变量使用final会不会提升性能的问题,完全看个人编码习惯,都可以。