AFAIK标准Java库中没有一种有效的方法来解析子字符串中的整数,而不实际新建一个包含子字符串的新字符串。
我正处于从字符串中解析数百万个整数的情况,我并不特别想为每个子字符串创建新的字符串。复制是我不需要的开销。
给定一个字符串s,我想要一个像:
这样的方法parseInteger(s, startOffset, endOffset)
语义如:
Integer.parseInt(s.substring(startOffset, endOffset))
现在,我知道我可以这样合理地写这个:
public static int parse(String s, int start, int end) {
long result = 0;
boolean foundMinus = false;
while (start < end) {
char ch = s.charAt(start);
if (ch == ' ')
/* ok */;
else if (ch == '-') {
if (foundMinus)
throw new NumberFormatException();
foundMinus = true;
} else if (ch < '0' || ch > '9')
throw new NumberFormatException();
else
break;
++start;
}
if (start == end)
throw new NumberFormatException();
while (start < end) {
char ch = s.charAt(start);
if (ch < '0' || ch > '9')
break;
result = result * 10 + (int) ch - (int) '0';
++start;
}
while (start < end) {
char ch = s.charAt(start);
if (ch != ' ')
throw new NumberFormatException();
++start;
}
if (foundMinus)
result *= -1;
if (result < Integer.MIN_VALUE || result > Integer.MAX_VALUE)
throw new NumberFormatException();
return (int) result;
}
但这不是重点。我宁愿从经过测试,支持的第三方库中获取此信息。例如,解析long并使用Long.MIN_VALUE正确处理有点微妙,我通过将int解析为long来欺骗。如果解析的整数大于Long.MAX_VALUE。上面仍然存在溢出问题。
有没有这样的图书馆?
我的搜索结果很少。
答案 0 :(得分:5)
你有没有想过你的应用?您找到了问题的根源吗?
由于Strings
是不可变的,因此很有可能需要很少的内存,并且很少有操作来创建子字符串。
除非你真的遇到内存,垃圾收集等问题,否则只需使用substring方法。 不要为您没有的问题寻求复杂的解决方案。
此外:如果你自己实施某些东西,你可能会失去比效率更高的收益。您的代码做了很多而且非常复杂 - 但是对于默认实现,您可能非常确定它相对较快。并且没有错误。
答案 1 :(得分:2)
我无法抗拒衡量你方法的改进:
package test;
public class TestIntParse {
static final int MAX_NUMBERS = 10000000;
static final int MAX_ITERATIONS = 100;
public static void main(String[] args) {
long timeAvoidNewStrings = 0;
long timeCreateNewStrings = 0;
for (int i = 0; i < MAX_ITERATIONS; i++) {
timeAvoidNewStrings += test(true);
timeCreateNewStrings += test(false);
}
System.out.println("Average time method 'AVOID new strings': " + (timeAvoidNewStrings / MAX_ITERATIONS) + " ms");
System.out.println("Average time method 'CREATE new strings': " + (timeCreateNewStrings / MAX_ITERATIONS) + " ms");
}
static long test(boolean avoidStringCreation) {
long start = System.currentTimeMillis();
for (int i = 0; i < MAX_NUMBERS; i++) {
String value = Integer.toString((int) Math.random() * 100000);
int intValue = avoidStringCreation ? parse(value, 0, value.length()) : parse2(value, 0, value.length());
String value2 = Integer.toString(intValue);
if (!value2.equals(value)) {
System.err.println("Error at iteration " + i + (avoidStringCreation ? " without" : " with") + " string creation: " + value + " != " + value2);
}
}
return System.currentTimeMillis() - start;
}
public static int parse2(String s, int start, int end) {
return Integer.valueOf(s.substring(start, end));
}
public static int parse(String s, int start, int end) {
long result = 0;
boolean foundMinus = false;
while (start < end) {
char ch = s.charAt(start);
if (ch == ' ')
/* ok */;
else if (ch == '-') {
if (foundMinus)
throw new NumberFormatException();
foundMinus = true;
} else if (ch < '0' || ch > '9')
throw new NumberFormatException();
else
break;
++start;
}
if (start == end)
throw new NumberFormatException();
while (start < end) {
char ch = s.charAt(start);
if (ch < '0' || ch > '9')
break;
result = result * 10 + ch - '0';
++start;
}
while (start < end) {
char ch = s.charAt(start);
if (ch != ' ')
throw new NumberFormatException();
++start;
}
if (foundMinus)
result *= -1;
if (result < Integer.MIN_VALUE || result > Integer.MAX_VALUE)
throw new NumberFormatException();
return (int) result;
}
}
结果:
Average time method 'AVOID new strings': 432 ms
Average time method 'CREATE new strings': 500 ms
你的方法在时间上大约高出14%,据说在内存中,虽然相当复杂(并且容易出错)。从我的角度来看,你的方法并没有得到回报,尽管你可能会这样做。
答案 2 :(得分:1)
如果您没有遇到实际的性能问题,请不要过于担心对象。使用当前的JVM,在性能和内存开销方面有永久性的改进。
如果您希望共享基础字符串的子字符串,可以查看Google协议缓冲区中的“ByteString”: