【问题标题】:Is concatenating with an empty string to do a string conversion really that bad?与空字符串连接以进行字符串转换真的那么糟糕吗?
【发布时间】:2011-01-31 04:17:05
【问题描述】:

假设我有两个char 变量,稍后我想将它们连接成一个字符串。我会这样做:

char c1, c2;
// ...

String s = "" + c1 + c2;

我见过有人说"" +“把戏”是“丑陋的”等等,你应该改用String.valueOfCharacter.toString。我更喜欢这种结构,因为:

  • 如果可能,我更喜欢使用语言功能而不是 API 调用
    • 一般来说,语言不是比 API 更稳定吗?
    • 如果语言特性只隐藏API调用,那么更有理由更喜欢它!
      • 更抽象!隐藏很好!
  • 我喜欢c1c2 在视觉上处于同一水平
    • String.valueOf(c1) + c2 暗示 c1 有一些特别之处
  • 它更短。

为什么String.valueOfCharacter.toString"" + 更可取,真的有很好的论据吗?


琐事:在java.lang.AssertionError 中,以下行出现了 7 次,每次都有不同的类型:

    this("" + detailMessage);

【问题讨论】:

  • 当然String.valueOf(c1) + c2 会很奇怪,如果你沿着这条路走,你会写String.valueOf(c1) + String.valueOf(c2)
  • @NomeN: 你可以写new String(new char[] {c1, c2})
  • 广告琐事:Java SE 核心库并不完全是良好编码风格的源泉,这是众所周知的 ;-)
  • @Joachim Sauer 是的,这是另一种方法。我只是想指出,转换一个而不转换另一个有点荒谬。正如 OP 正确地说的那样,它会错误地暗示正在发生一些特别的事情。
  • 在此处查找相关问题:stackoverflow.com/questions/1572708/…

标签: java string coding-style


【解决方案1】:

在我看来,"" + var 风格有一个非常大的问题。它只是使用var 的toString 方法。因此,如果将 var 的类型更改为其他类型,则不会出现异常。我刚刚遇到的一个很好的例子是类型从int 更改为Optional<Integer>。代码仍然可以正常编译,但您会得到完全不同的结果。

【讨论】:

    【解决方案2】:

    最好的方法是编译/反编译你的代码,我用了 Jad http://en.wikipedia.org/wiki/JAD_(JAva_Decompiler),你会看到你的表达式被转换成

    String s = (new StringBuilder()).append("").append(ci).append(c2).toString();

    你可以看到 javac 实际上包含了 append("") 调用,但是它的成本可以忽略不计,注意附加到内部 StringBuilder 缓冲区,你可以查看 StringBuilder 的源代码

    【讨论】:

      【解决方案3】:

      我更喜欢使用String.valueOf 进行单次 转换 - 但在您的情况下,您确实需要串联。

      但是,我建议这个版本将消除所有潜在的歧义:

      String s = c1 + "" + c2;
      

      这样,无论多么遥远,都不可能有人在连接之前考虑是否将 c1 和 c2 相加。

      【讨论】:

        【解决方案4】:

        怎么样

        new String(new char[] {a, b})
        

        如果你经常这样做,你可以创建一个“字符串”类:

        public static String valueOf(char... chars) {
            return new String(chars);
        }
        

        然后您的行将读取

        String s = Strings.valueOf(a, b);
        

        又好又短。

        已编辑

        一个更好的名字可能是:

        String s = Chars.asString(a, b);
        

        【讨论】:

        • 也应该很快,因为唯一要做的就是一个数组拷贝,速度很快。
        • -1 没有人 不用看调用的方法就知道它做了什么。请重构!
        • @Thorbjørn:有什么建议吗? 建设性的批评总是受欢迎的。
        • 我可能会命名类 CharHelper(CharUtils 是另一个候选对象)和方法 charsToString,使行 String s = CharHelper.charsToString(a, b)
        • 在我看来,一个 javadoc 注释就足够了。 jdk里面有很多方法,没有说明就没用。在一个名为 Strings 的类中有一个方法,它接受一个 char 数组并生成一个 String 对我来说似乎相对简单。你的建议太冗长了。 Chars.asString(char... chars) 可能是一个不错的选择。
        【解决方案5】:

        除非您的应用需要每一盎司的性能,否则请编写更快速且更易于阅读的代码。 "" + 是一种执行速度较慢的语法,但每次我使用它时似乎都更容易阅读。

        【讨论】:

          【解决方案6】:

          我认为"" + var 中的+ 实际上是重载来进行转换的:

          Java 语言为字符串连接运算符 ( + ) 以及将其他对象转换为字符串提供了特殊支持。字符串连接是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,由 Object 定义并由 Java 中的所有类继承。有关字符串连接和转换的更多信息

          所以从技术角度来看没有区别也没有问题。

          形成可读性的观点 - 这是个人喜好或团队内商定的编码风格的问题。

          【讨论】:

          • 我刚刚在问题中添加了 [coding-style] 标签;这就是它的主要内容。
          【解决方案7】:

          在我看来,"" + x 可读性强、简短且准确。我更喜欢它而不是像String.valueOf 这样的更长的构造。这种行为是明确定义的,而且它的使用非常普遍,以至于我发现很难将其称为 hack。

          我唯一稍微担心的是性能——而且我非常肯定这通常并不重要(即使我没有测量或查看二进制文件)。这种 concat 也很有可能被优化掉,因为它应该很容易检测到(不过这只是一个猜测)。

          【讨论】:

          • 如果您的代码循环运行数十万次,这非常重要。
          • 没有人会在循环中使用它——在循环中你总是使用最知名的高性能代码。在 99% 的情况下,这不是问题。 imo,一般情况下的可读性要重要得多。
          【解决方案8】:

          这种结构的问题在于它通常不表达意图。

          它表示一个字符串与另一个值的连接,但连接通常不是这一行的目标。

          在您演示的特定情况下,串联实际上是目标,因此此代码确实表达了意图。

          在这种方法的更常见用法(String s = "" + intValue;)中,连接只是一种可以容忍的副作用,而intValue 的转换是实际目标。一个简单的String.valueOf(intValue) 更清楚地表达了这个意图。

          【讨论】:

          • 我不这么认为。 "" + x 非常常见,意图应该很明确。
          • @mafutrct:如果仅在您之前多次看到该确切构造时才清楚意图,那么它就不清楚了。它只是证明模式识别有效。
          • @polygenelubricants:够公平的!
          • @Chris:让我试着改写你的论点:“这并不难看,因为它很常见。”这对我来说听起来不对。
          • @Chris:那我误读了你的评论,对不起。但这是否意味着应该使用它?
          【解决方案9】:

          你的论点是好的;这是 Java 语言中表现力更强的领域之一,正如您所发现的,"" + 习语似乎根深蒂固。

          请参阅 JLS 中的 String concatenation。像

          这样的表达式
          "" + c1 + c2
          

          等价于

          new StringBuffer().append(new Character(c1).toString())
                            .append(new Character(c2).toString()).toString()
          

          除了所有中间对象都不是必需的(因此效率不是动机)。规范说实现可以使用StringBuffer 或不使用。由于此功能已内置于语言中,我认为没有理由使用更冗长的形式,尤其是在已经很冗长的语言中。

          【讨论】:

          • 其实,没有。 JLS 以这种方式解释它,但编译器以不同的方式实现它。 Eclipse 编译器生成等效于 new StringBuilder().append(c1).append(c2).toString() 的字节码 javac 编译器 (1.5) 生成等效于 new StringBuilder().append("").append(c1) 的字节码.append(c2).toString()
          猜你喜欢
          • 2013-02-17
          • 2011-03-04
          • 2014-12-13
          • 1970-01-01
          • 1970-01-01
          • 2011-12-06
          • 2011-03-12
          • 2015-01-13
          • 1970-01-01
          相关资源
          最近更新 更多