我刚刚在我的项目中找到了一些sql查询构建:
return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();这个StringBuilder是否达到了它的目标,即减少内存使用?
我对此表示怀疑,因为在构造函数中使用了'+‘(字符串连接运算符)。这会占用与使用如下代码的字符串相同的内存量吗?据我所知,使用StringBuilder.append()时会有所不同。
return "select id1, " + " id2 " + " from " + " table";这两条语句的内存使用量是否相等?请澄清。
提前感谢!
编辑:
顺便说一句,这不是我的代码。在一个老项目里找到的。此外,查询也不像我的示例中的查询那么小。:)
发布于 2012-01-04 19:04:50
使用StringBuilder的目的,即减少内存。它实现了吗?
没关系,您请。该代码没有正确使用StringBuilder。(我认为您错误地引用了它;id2和table周围肯定没有引用?)
请注意,目标(通常)是减少内存混乱,而不是总内存使用量,以使垃圾收集器的工作变得更容易。
会占用相当于使用如下字符串的内存吗?
不,它会引起更多的记忆混乱,而不仅仅是你引用的直连词。(直到/除非JVM优化器发现代码中的显式StringBuilder是不必要的,并在可能的情况下将其优化。)
如果代码的作者想要使用StringBuilder (有支持的论点,也有反对的论点;请参阅本答案末尾的注释),最好正确地使用它(在这里,我假设id2和table周围实际上没有引号):
StringBuilder sb = new StringBuilder(some_appropriate_size);
sb.append("select id1, ");
sb.append(id2);
sb.append(" from ");
sb.append(table);
return sb.toString();注意,我已经在StringBuilder构造函数中列出了some_appropriate_size,所以它一开始就有足够的容量来容纳我们将要追加的全部内容。如果不指定,则使用的缺省大小是16 characters,它通常太小,导致StringBuilder不得不进行重新分配以使自己更大(在Sun/Oracle JDK中,如果它知道每次耗尽空间时都需要更多的空间来满足特定的append,则它会将自己加倍或更多)。
您可能听说过,如果使用Sun/Oracle编译器进行编译,字符串连接将在幕后使用StringBuilder。这是真的,它将使用一个StringBuilder作为整个表达式。但它将使用默认构造函数,这意味着在大多数情况下,它将不得不进行重新分配。不过,它更容易阅读。请注意,对于一系列连接,情况并非如此。例如,这使用了一个StringBuilder
return "prefix " + variable1 + " middle " + variable2 + " end";它大致翻译为:
StringBuilder tmp = new StringBuilder(); // Using default 16 character size
tmp.append("prefix ");
tmp.append(variable1);
tmp.append(" middle ");
tmp.append(variable2);
tmp.append(" end");
return tmp.toString();所以这没问题,尽管默认构造函数和随后的重新分配并不理想,但很可能它已经足够好了-而且连接的可读性要好得多。
但这仅适用于单个表达式。多个StringBuilder用于此操作:
String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;最终会变成这样:
String s;
StringBuilder tmp;
s = "prefix ";
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable1);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" middle ");
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable2);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" end");
s = tmp.toString();
return s;...which相当难看。
但是,重要的是要记住,除了极少数情况外,在所有情况下都无关紧要,除非出现特定的性能问题,否则最好使用可读性(增强了可维护性)。
发布于 2012-01-04 19:09:16
当你已经拥有了你想要追加的所有“片段”时,使用StringBuilder就没有任何意义了。根据您的示例代码,在同一调用中使用StringBuilder和字符串连接甚至更糟糕。
这样会更好:
return "select id1, " + " id2 " + " from " + " table";在本例中,字符串连接实际上发生在编译时,因此它等同于更简单的:
return "select id1, id2 from table";在这种情况下,使用new StringBuilder().append("select id1, ").append(" id2 ")....toString()实际上会影响性能,因为它强制在执行时执行连接,而不是在编译时执行连接。糟了。
如果真正的代码是通过在查询中包含值来构建SQL查询,那么这是另一个单独的问题,即您应该使用参数化查询,在参数中指定值,而不是在SQL中指定值。
在StringBuilder出现之前,我有一个article on String / StringBuffer是我写的。不过,这些原则也同样适用于StringBuilder。
发布于 2014-07-26 02:34:56
[这里有一些很好的答案,但我发现他们仍然缺乏一点信息。]
return (new StringBuilder("select id1, " + " id2 " + " from " + " table"))
     .toString();因此,正如您所指出的,您给出的示例过于简单,但不管怎样,让我们分析它。因为"select id1, " + " id2 " + " from " + " table"都是常量,所以编译器实际上在这里做了+的工作。所以这就变成了:
return new StringBuilder("select id1,  id2  from  table").toString();显然,在这种情况下,使用StringBuilder是没有意义的。你也可以这样做:
// the compiler combines these constant strings
return "select id1, " + " id2 " + " from " + " table";但是,即使您附加了任何字段或其他非常量,编译器也会使用内部StringBuilder --您不需要定义它:
// an internal StringBuilder is used here
return "select id1, " + fieldName + " from " + tableName;在幕后,这变成了大致等同于:
StringBuilder sb = new StringBuilder("select id1, ");
sb.append(fieldName).append(" from ").append(tableName);
return sb.toString();实际上,只有当你有条件代码时,你才需要直接使用StringBuilder。例如,如下所示的代码非常需要StringBuilder
// 1 StringBuilder used in this line
String query = "select id1, " + fieldName + " from " + tableName;
if (where != null) {
   // another StringBuilder used here
   query += ' ' + where;
}第一行中的+使用一个StringBuilder实例。然后+=使用另一个StringBuilder实例。这样做效率更高:
// choose a good starting size to lower chances of reallocation
StringBuilder sb = new StringBuilder(64);
sb.append("select id1, ").append(fieldName).append(" from ").append(tableName);
// conditional code
if (where != null) {
   sb.append(' ').append(where);
}
return sb.toString();另一次我使用StringBuilder是当我从许多方法调用中构建一个字符串时。然后,我可以创建接受StringBuilder参数的方法:
private void addWhere(StringBuilder sb) {
   if (where != null) {
      sb.append(' ').append(where);
   }
}当您使用StringBuilder时,您应该同时注意+的任何用法:
sb.append("select " + fieldName);该+将导致创建另一个内部StringBuilder。这当然应该是:
sb.append("select ").append(fieldName);最后,正如@T.J.rowder所指出的,您应该始终猜测StringBuilder的大小。这将节省在增加内部缓冲区大小时创建的char[]对象的数量。
https://stackoverflow.com/questions/8725739
复制相似问题