【问题标题】:Storing in variable vs. having multiple different methods存储在变量中与具有多种不同的方法
【发布时间】:2013-03-08 09:49:20
【问题描述】:

使用这个有什么优缺点:

String a = new String();
switch (i) {
case 1: a = "Cueck"; break;
case 2: a = "Blub"; break;
case 3: a = "Writing cases is BORING!"; break;
}
System.out.println(a);

对比:

switch (i) {
case 1: System.out.println("Cueck"); break;
case 2: System.out.println("Blub"); break;
case 3: System.out.println("Writing cases is BORING!"); break;
}

哪个生成更好的字节码?哪个生成更多的字节码?

【问题讨论】:

  • 我建议您获取 ASM 字节码大纲并自行测试。 :)
  • 除非它被执行 420 亿次,否则我不会担心它......这个问题只是理论上的问题,还是真正的问题?
  • 我建议你使用第二种方法,因为只创建了 3 个 String 文字,而在第一个中,有 4 个 String 对象
  • 这两个程序对于实例的行为不同,i=0)
  • 建议您从顶级示例中删除 = new String() 并在您的 switch 语句中添加默认情况。

标签: java variables switch-statement bytecode


【解决方案1】:

您的第一个选项更简洁,冗余代码更少。一项建议更改:

String a;

switch (i) {
  case 1: a = "Cueck"; break;
  case 2: a = "Blub"; break;
  case 3: a = "Writing cases is BORING!"; break;
  default: throw new IllegalStateException("Unknown option!");
}

System.out.println(a);

不要不必要地创建字符串 - a 应该在需要时被实例化。默认情况应抛出异常或将a 设置为默认值。

哪个生成更好的字节码?哪个生成更多的字节码?

我不会担心这个。在我看来,这并不是任何现实应用程序中可能存在的瓶颈。此外,您无法确定一旦您的应用程序运行,JVM 将如何优化字节码。

【讨论】:

  • 也永远不要打电话给new String(),因为这会与String interning混淆。
  • @bmorris591 你有这方面的参考吗?
  • 我的意思是,如果你直接调用构造函数,String 不会被实习,从spec 只有“编译时间常数”Strings 被实习。
【解决方案2】:

使用javap -c classname可以自己检查字节码,

这是选项 1:

(注意,我必须初始化 a = null 否则无法编译)

   7:   aconst_null
   8:   astore_2
   9:   iload_1
   10:  tableswitch{ //1 to 3
                1: 36;
                2: 42;
                3: 48;
                default: 51 }
   36:  ldc     #3; //String Cueck
   38:  astore_2
   39:  goto    51
   42:  ldc     #4; //String Blub
   44:  astore_2
   45:  goto    51
   48:  ldc     #5; //String Writing cases is BORING!
   50:  astore_2
   51:  getstatic       #6; //Field java/lang/System.out:Ljava/io/PrintStream;
   54:  aload_2
   55:  invokevirtual   #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   58:  return

这里是选项 2:

   7:   iload_1
   8:   tableswitch{ //1 to 3
                1: 36;
                2: 47;
                3: 58;
                default: 66 }
   36:  getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   39:  ldc     #4; //String Cueck
   41:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   44:  goto    66
   47:  getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   50:  ldc     #6; //String Blub
   52:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   55:  goto    66
   58:  getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   61:  ldc     #7; //String Writing cases is BORING!
   63:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   66:  return

就个人而言,我认为在这种情况下没有更好的字节码,我发现选项 1 更具可读性。

【讨论】:

    【解决方案3】:

    我认为字节码大小不会有太大差异,但我建议采用第一种方法。如果您在将来的某些代码更改中决定不调用System.out.println(a) 而调用logger.debug(a),那么您将只在一处而不是在所有case 开关上进行更改。

    【讨论】:

      猜你喜欢
      • 2013-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多