如何防止“注意:'StringBuilder sb'可以用intellij-idea中的'String'替换”

时间:2017-03-17 11:10:17

标签: java intellij-idea

当我使用IDE - “IDEA 14.03”时,它总是给我这个通知。注意:'StringBuilder sb'可以替换为'String'

以下是详细信息,当我定义名为“sb”的对象时,对象类是“StringBuilder”。这是我尝试过的代码段:

idx = df.index.difference(df.loc['2015-11-07'].index)
print (idx)
DatetimeIndex(['2015-11-08 00:45:00'], dtype='datetime64[ns]', name='time', freq=None)

print (df.loc[idx])
                          price
time                           
2015-11-08 00:45:00  180.216667

我只想知道如果将“StringBuilder”更改为“String”有什么好处。为什么IDE总是通知我更改类类型?

5 个答案:

答案 0 :(得分:9)

我认为为了理解IDE为什么要将StringBuilder更改为String,你应该理解String,StringBuffer和StringBuilder之间的区别。

字符串是不可变的。这意味着如果您想要从字符串中更改某些内容,则不会删除原始字符串,而是创建一个新字符串,其中包括您的更改。 StringBuffer和StringBuilder是可变的。这意味着对您的更改,原始字符串将相应更改。

它们之间的另一个主要区别是String和StringBuffer是线程安全的,而StringBuilder则不是。还有其他差异,请查看this site以了解有关差异的更多信息。

如果你将String与StringBuilder进行比较,在大多数情况下,使用String更实际和合乎逻辑,如果你不知道,你用你的字符串做什么。

将字符串与加号(+)连接并不总是更好。例如,如果由于其可变性而在循环中更改字符串,则StringBuilder的append方法更符合逻辑。请阅读代码中的注释;

String a;
StringBuilder b;
for(int i=0; i<5; i++)
{
a += i; //String is immutable and in each iteration, a new object will be created
b.append(i); //StringBuilder is mutable and in each iteration, the existing string will be used.
}

您的IDE所做的只是向您展示最佳实践。这就是为什么,它被称为推荐。

如果你想继续前进,不要让Intellij向你发出警告;您可以禁用警告,如;

enter image description here

修改

@ CrazyCoder的评论在这里需要注意。

IDE在这里实际上非常聪明,它建议你改变它以获得更好的代码可读性,因为内部编译器将生成完全相同的字节码,并且你的代码将具有相同的性能和相同的内存使用,但它将更容易阅读。您可以获得可读性优势,而不会影响性能。很久以前就问了answered in IntelliJ IDEA forum类似的问题。

答案 1 :(得分:4)

我知道这是一个老问题,已经回答了一个非常好的答案,但只是一个微不足道的评论: 在这种情况下,为了便于阅读,(并且由于编译器的行为与Ad提到的相同),我会使用String.format。 而不是

StringBuilder sb = new StringBuilder("status=").append(status).append(" ,msg=").append(msg);

我发现这更具可读性:

String.format("status=%s, msg=%s", status, msg);

答案 2 :(得分:1)

  

为什么IDE总是通知我更改类类型

java 8:代码的效果相同,但是字符串串联

String r = s1 + s2;

更具可读性

答案 3 :(得分:1)

因为code 1

String s1 = "a";
String s2 = "b";
String result = s1 + s2;

code 2

String s1 = "a";
String s2 = "b";
String result = new StringBuilder().append(s1).append(s2).toString();

编译成bytecode后,两段代码的结果是一样的。 code 1 将被编译器优化为 StringBuilder 中的 bytecode

   L0
    LINENUMBER 15 L0
    LDC "a"
    ASTORE 1
   L1
    LINENUMBER 16 L1
    LDC "b"
    ASTORE 2
   L2
    LINENUMBER 17 L2
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    ALOAD 1
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ASTORE 3
   L3
    LINENUMBER 18 L3
    RETURN
   L4
    LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
    LOCALVARIABLE s1 Ljava/lang/String; L1 L4 1
    LOCALVARIABLE s2 Ljava/lang/String; L2 L4 2
    LOCALVARIABLE result Ljava/lang/String; L3 L4 3
    MAXSTACK = 2
    MAXLOCALS = 4

bytecode的角度来看,IDAE认为这两种写法是等价的,而code 1的写法更简洁。所以建议使用code 1

ps:不喜欢的可以关掉这个提示:)

以上测试基于jdk1.8

答案 4 :(得分:0)

尽管使用String串联更容易阅读代码,但对于Java 8及以下版本,这是通过StringBuilder实现的,因此从表面上看,这似乎在伤害您自己。

但是,StringBuilder的默认容量为16。如果您深入研究StringBuilder的源代码,您将看到realloc使用:

         int newCapacity = (value.length << 1) + 2;

因此,基本上每次您都会翻倍。因此,对于任意长度的字符串(例如100),您将最终分配空间并复制4次,容量分别为16、32、64,最后是128。

但是,您可以执行以下操作:

new StringBuffer(128).sb.append("status=").append(status).append(" ,msg=").append(msg).toString();

而且,您已经为自己保存了3个分配和数组副本。

据我了解,Java 9+具有更好的解决方案。因此,在知道这将是固定的之后,我通常使用Strings,除非我知道性能是一个问题,然后再还原StringBuilder的。如果您在嵌入式系统或Android上工作,因为资源稀缺,肯定是这种情况。在云服务器上,没有那么多。

对于IntelliJ检查器,我将其关闭,但是我通常在注释中添加JAVA10标签,以便稍后找到它们并在迁移到10时将其还原。也许,我只需要记住重新-启用检查器。 :)

PS-我喜欢Udi的回答。我将研究实现。