如果在 Java 中使用 toString 修改字符串时 StringBuilder 的效率
Efficiency of StringBuilder when Modifying String if using toString in Java
我的任务是优化使用 Cognos SDK 开发的应用程序,该应用程序查询 Content Store 中的所有包,然后将它们写入 SQL 数据库。该应用程序是由我担任该角色的前任编写的,它做了一些有趣的事情......它有几个我禁用的手动 system.GC 调用,以及一个循环中的 System.wait(2000) .目前它在服务器架构上 运行 会快得多,但如果试图在普通客户端上 运行 它会由于堆错误而崩溃。所以深入挖掘,我发现里面有成吨的弦。显而易见的答案是更改为 StringBuilder,但如果我不得不在其中使用大量 "toString",我真的可以节省任何内存吗?从理论上讲,这些字符串运算符中的每一个都应该有一个方法,但我有点不愿意弄乱应用程序的某些逻辑,我不得不查找如何具体执行每个操作。如果之前有人问过这个问题,我深表歉意,但环顾四周后我找不到一个。
(小题外话:整个方法的认知复杂度为 174,但其中相当一部分是特定于 cognos 的,我不知道从哪里开始降低它。)
这是我所做更改的示例(此循环在约 450000 行输入上 运行 多次)。此外,我将 "express" 更改为初始值为 "" 的 StringBuilder,在 for 循环之前不久,这是以下内容的一部分:
if (element.hasAttribute("expression") && element.getAttribute("expression") != "") {
formula = element.getAttribute("expression");
for (int k = 0; k < formula.length(); k++) {
if (formula.charAt(k) == '<')
exSearch++;
if (exSearch == 0)
express.append(formula.charAt(k));
if (formula.charAt(k) == '>')
exSearch--;
}
express.replace(0, express.length(),express.toString().replaceAll("\s", ""));
express.replace(0, express.length(),express.toString().replaceAll(">", "<"));
express.replace(0, express.length(),express.toString().replaceAll("<", ">"));
express.replace(0, express.length(),express.toString().replaceAll("'", "'"));
express.replace(0, express.length(),express.toString().replaceAll("&", "&"));
}
if (express.length() > 1000) {
express.replace(0, express.length(),express.toString().substring(0, 995) + "..." );
}
table = "CALCULATION";
tableLoc = "CALCULATION";
inBrackets = false;
if (express.indexOf("[")== 0) {
String[] temp = express.toString().split("].");
if (temp.length > 1 && temp[temp.length - 1].length() > 1) {
table = temp[temp.length - 2].substring(1);
tableLoc = temp[temp.length - 1].substring(1, temp[temp.length - 1].length() - 1);
}
}
原文:
if (element.hasAttribute("expression") && element.getAttribute("expression") != "") {
formula = element.getAttribute("expression");
for (int k = 0; k < formula.length(); k++) {
if (formula.charAt(k) == '<')
exSearch++;
if (exSearch == 0)
express += formula.charAt(k);
if (formula.charAt(k) == '>')
exSearch--;
}
express = express.replaceAll("\s", "");
express = express.replaceAll(">", "<");
express = express.replaceAll("<", ">");
express = express.replaceAll("'", "'");
express = express.replaceAll("&", "&");
}
if (express.length() > 1000) {
express = express.substring(0, 995) + "...";
}
table = "CALCULATION";
tableLoc = "CALCULATION";
inBrackets = false;
if (express.startsWith("[")) {
String[] temp = express.split("].");
if (temp.length > 1 && temp[temp.length - 1].length() > 1) {
table = temp[temp.length - 2].substring(1);
tableLoc = temp[temp.length - 1].substring(1, temp[temp.length - 1].length() - 1);
}
}
是的,将字符串运算替换为 StringBuilder 会对内存和性能产生影响。但是您的新代码仍在对所有 toString().replaceAll 和 toString().split 以及 toString().substring() 调用进行大量字符串运算。摆脱所有这些。它们都很昂贵,而且完全没有必要。
不要对字符串进行任何操作,在单个 StringBuilder 实例上进行所有操作。
至于 运行 内存不足,这些字符串中的大部分都被垃圾回收了,所以不清楚这是否会解决内存问题。但它肯定会改善情况。
求大神改造
express = express.replaceAll("\s", "");
express = express.replaceAll(">", "<");
express = express.replaceAll("<", ">");
express = express.replaceAll("'", "'");
express = express.replaceAll("&", "&");
进入
express = express.replace("\s", "").replace(">", "<").replace("<", ">").replace("'", "'").replace("&", "&")
我的任务是优化使用 Cognos SDK 开发的应用程序,该应用程序查询 Content Store 中的所有包,然后将它们写入 SQL 数据库。该应用程序是由我担任该角色的前任编写的,它做了一些有趣的事情......它有几个我禁用的手动 system.GC 调用,以及一个循环中的 System.wait(2000) .目前它在服务器架构上 运行 会快得多,但如果试图在普通客户端上 运行 它会由于堆错误而崩溃。所以深入挖掘,我发现里面有成吨的弦。显而易见的答案是更改为 StringBuilder,但如果我不得不在其中使用大量 "toString",我真的可以节省任何内存吗?从理论上讲,这些字符串运算符中的每一个都应该有一个方法,但我有点不愿意弄乱应用程序的某些逻辑,我不得不查找如何具体执行每个操作。如果之前有人问过这个问题,我深表歉意,但环顾四周后我找不到一个。
(小题外话:整个方法的认知复杂度为 174,但其中相当一部分是特定于 cognos 的,我不知道从哪里开始降低它。)
这是我所做更改的示例(此循环在约 450000 行输入上 运行 多次)。此外,我将 "express" 更改为初始值为 "" 的 StringBuilder,在 for 循环之前不久,这是以下内容的一部分:
if (element.hasAttribute("expression") && element.getAttribute("expression") != "") {
formula = element.getAttribute("expression");
for (int k = 0; k < formula.length(); k++) {
if (formula.charAt(k) == '<')
exSearch++;
if (exSearch == 0)
express.append(formula.charAt(k));
if (formula.charAt(k) == '>')
exSearch--;
}
express.replace(0, express.length(),express.toString().replaceAll("\s", ""));
express.replace(0, express.length(),express.toString().replaceAll(">", "<"));
express.replace(0, express.length(),express.toString().replaceAll("<", ">"));
express.replace(0, express.length(),express.toString().replaceAll("'", "'"));
express.replace(0, express.length(),express.toString().replaceAll("&", "&"));
}
if (express.length() > 1000) {
express.replace(0, express.length(),express.toString().substring(0, 995) + "..." );
}
table = "CALCULATION";
tableLoc = "CALCULATION";
inBrackets = false;
if (express.indexOf("[")== 0) {
String[] temp = express.toString().split("].");
if (temp.length > 1 && temp[temp.length - 1].length() > 1) {
table = temp[temp.length - 2].substring(1);
tableLoc = temp[temp.length - 1].substring(1, temp[temp.length - 1].length() - 1);
}
}
原文:
if (element.hasAttribute("expression") && element.getAttribute("expression") != "") {
formula = element.getAttribute("expression");
for (int k = 0; k < formula.length(); k++) {
if (formula.charAt(k) == '<')
exSearch++;
if (exSearch == 0)
express += formula.charAt(k);
if (formula.charAt(k) == '>')
exSearch--;
}
express = express.replaceAll("\s", "");
express = express.replaceAll(">", "<");
express = express.replaceAll("<", ">");
express = express.replaceAll("'", "'");
express = express.replaceAll("&", "&");
}
if (express.length() > 1000) {
express = express.substring(0, 995) + "...";
}
table = "CALCULATION";
tableLoc = "CALCULATION";
inBrackets = false;
if (express.startsWith("[")) {
String[] temp = express.split("].");
if (temp.length > 1 && temp[temp.length - 1].length() > 1) {
table = temp[temp.length - 2].substring(1);
tableLoc = temp[temp.length - 1].substring(1, temp[temp.length - 1].length() - 1);
}
}
是的,将字符串运算替换为 StringBuilder 会对内存和性能产生影响。但是您的新代码仍在对所有 toString().replaceAll 和 toString().split 以及 toString().substring() 调用进行大量字符串运算。摆脱所有这些。它们都很昂贵,而且完全没有必要。
不要对字符串进行任何操作,在单个 StringBuilder 实例上进行所有操作。
至于 运行 内存不足,这些字符串中的大部分都被垃圾回收了,所以不清楚这是否会解决内存问题。但它肯定会改善情况。
求大神改造
express = express.replaceAll("\s", "");
express = express.replaceAll(">", "<");
express = express.replaceAll("<", ">");
express = express.replaceAll("'", "'");
express = express.replaceAll("&", "&");
进入
express = express.replace("\s", "").replace(">", "<").replace("<", ">").replace("'", "'").replace("&", "&")