Vaa*_*ndu 88 java string stringbuilder
我刚在我的项目中发现了一些这样的sql查询构建:
return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();
Run Code Online (Sandbox Code Playgroud)
这是否StringBuilder
达到了目标,即减少内存使用量?
我对此表示怀疑,因为在构造函数中使用了'+'(String concat运算符).这会占用与使用String相同的内存量,如下面的代码吗?我明白了,它在使用时有所不同StringBuilder.append()
.
return "select id1, " + " id2 " + " from " + " table";
Run Code Online (Sandbox Code Playgroud)
这两个语句在内存使用方面是否相同?请澄清.
提前致谢!
编辑:
顺便说一下,这不是我的代码.在一个旧项目中找到它.此外,查询不是我的示例中的查询.:)
T.J*_*der 182
使用StringBuilder的目的,即减少内存.它实现了吗?
一点都不.该代码未StringBuilder
正确使用.(我认为你错误引用了它;肯定没有引号id2
和table
?)
请注意,目标(通常)是减少内存流失而不是使用的总内存,以使垃圾收集器的生活更轻松.
将内存等同于使用如下所示的String吗?
不,它会导致更多的内存流失,而不仅仅是你所引用的直接连接.(直到/除非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();
Run Code Online (Sandbox Code Playgroud)
请注意,我已some_appropriate_size
在StringBuilder
构造函数中列出,因此它开始时具有足够的容量来容纳我们要追加的完整内容.如果不指定一个字符,则使用的默认大小为16个字符,这通常太小而导致StringBuilder
必须进行重新分配以使其自身更大(IIRC,在Sun/Oracle JDK中,它会使自身翻倍[或更多,如果它知道append
每次用完房间时需要更多来满足特定的要求.
您可能听说过,如果使用Sun/Oracle编译器进行编译,字符串连接将使用StringBuilder
隐藏.这是事实,它将使用一个StringBuilder
用于整体表达.但它将使用默认构造函数,这意味着在大多数情况下,它将不得不进行重新分配.不过,它更容易阅读.请注意,对于一系列连接,情况并非如此.例如,这使用一个:StringBuilder
return "prefix " + variable1 + " middle " + variable2 + " end";
Run Code Online (Sandbox Code Playgroud)
它大致翻译为:
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();
Run Code Online (Sandbox Code Playgroud)
所以没关系,虽然默认的构造函数和随后的重新分配(S)不理想,赔率是它不够好-以及级联是一个很大的可读性.
但这仅适用于单一表达.多个StringBuilder
s用于此:
String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;
Run Code Online (Sandbox Code Playgroud)
最终变成这样的事情:
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;
Run Code Online (Sandbox Code Playgroud)
......这很丑陋.
但重要的是要记住,在极少数情况下,除了特定性能问题之外,在所有情况下都无关紧要,并且具有可读性(增强可维护性)是首选.
Jon*_*eet 38
当你已经拥有了想要追加的所有"碎片"时,根本没有必要使用它StringBuilder
.根据您的示例代码在同一个调用中使用StringBuilder
和字符串连接更糟糕.
这会更好:
return "select id1, " + " id2 " + " from " + " table";
Run Code Online (Sandbox Code Playgroud)
在这种情况下,字符串连接实际上是在编译时发生的,因此它等同于更简单的:
return "select id1, id2 from table";
Run Code Online (Sandbox Code Playgroud)
在这种情况下,使用new StringBuilder().append("select id1, ").append(" id2 ")....toString()
实际上会阻碍性能,因为它会强制在执行时执行连接,而不是在编译时执行.哎呀.
如果真实代码通过在查询中包含值来构建SQL查询,那么这是另一个单独的问题,即您应该使用参数化查询,在参数中而不是在SQL中指定值.
我有一篇关于String
/StringBuffer
我之前写过的文章 - 之前有过StringBuilder
.这些原则StringBuilder
同样适用于此.
Gra*_*ray 10
[[这里有一些很好的答案,但我发现他们仍然缺乏一些信息.]]
return (new StringBuilder("select id1, " + " id2 " + " from " + " table"))
.toString();
Run Code Online (Sandbox Code Playgroud)
正如你所指出的那样,你给出的例子是一个简单的例子,但无论如何我们要分析它.这里发生的是编译器实际上在+
这里工作因为"select id1, " + " id2 " + " from " + " table"
都是常量.所以这变成了:
return new StringBuilder("select id1, id2 from table").toString();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,显然,使用没有意义StringBuilder
.你不妨这样做:
// the compiler combines these constant strings
return "select id1, " + " id2 " + " from " + " table";
Run Code Online (Sandbox Code Playgroud)
但是,即使您附加任何字段或其他非常量,编译器也会使用内部 StringBuilder
- 您无需定义一个:
// an internal StringBuilder is used here
return "select id1, " + fieldName + " from " + tableName;
Run Code Online (Sandbox Code Playgroud)
在封面下,这变成了大致相当于的代码:
StringBuilder sb = new StringBuilder("select id1, ");
sb.append(fieldName).append(" from ").append(tableName);
return sb.toString();
Run Code Online (Sandbox Code Playgroud)
真的是你需要StringBuilder
直接使用的唯一时间是你有条件代码.例如,看起来如下的代码迫切需要StringBuilder
:
// 1 StringBuilder used in this line
String query = "select id1, " + fieldName + " from " + tableName;
if (where != null) {
// another StringBuilder used here
query += ' ' + where;
}
Run Code Online (Sandbox Code Playgroud)
将+
在第一行使用一个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();
Run Code Online (Sandbox Code Playgroud)
我使用a的另一个时间是我StringBuilder
从许多方法调用构建一个字符串.然后我可以创建带StringBuilder
参数的方法:
private void addWhere(StringBuilder sb) {
if (where != null) {
sb.append(' ').append(where);
}
}
Run Code Online (Sandbox Code Playgroud)
当您使用a时StringBuilder
,您应该同时注意任何用法+
:
sb.append("select " + fieldName);
Run Code Online (Sandbox Code Playgroud)
这+
将导致StringBuilder
创建另一个内部.这当然应该是:
sb.append("select ").append(fieldName);
Run Code Online (Sandbox Code Playgroud)
最后,正如@TJrowder指出的那样,你应该总是猜测它的大小StringBuilder
.这将节省char[]
增加内部缓冲区大小时创建的对象数.
归档时间: |
|
查看次数: |
290858 次 |
最近记录: |