为什么不从这个 Java 流中过滤掉空字符串?
Why aren't empty strings filtered out of this Java stream?
我有一个流操作 (Java 8),旨在将一堆字符串解析为双精度数并求和。有些字符串是空的,但我不相信任何字符串都是空的。我已经添加了一个 filter
操作来在空的到达 Double.parseDouble()
之前过滤掉它们可能会导致错误,但过滤器似乎不起作用。
我的代码:
double myTotal= myObjectList.stream()
.map(myObject::getAmount)
.peek( s -> System.out.println("before filter: " + s) )
.filter( s -> !s.isEmpty() )
.peek( s -> System.out.println("after filter: " + s) )
.mapToDouble(Double::parseDouble)
.reduce(0D,Double::sum);
这是在 JSP 中,JSP 编译失败。根据错误页面,异常发生在最后一行 (.reduce(0D,Double::sum);
),但是 "root cause" 是一个“java.lang.NumberFormatException: empty String
” -- Double.parseDouble()
is encountering empty strings.
我尝试了几种 filter
操作的排列组合,包括一些检查 null 和一些检查 !s.equals("")
等。我添加了用于调试的 peek
操作,很明显 before 和 after [=12] 都打印了一个空字符串=]行。
我做错了什么?有没有更好的方法来过滤掉无法解析为双精度的值?
可能是空格,你可以先trim()
字符串,然后检查它是否为空,同时删除空格字符串,如:
double myTotal= myObjectList.stream()
.map(myObject::getAmount)
.peek( s -> System.out.println("before filter: " + s) )
.filter( s -> !s.trim().isEmpty() )
.peek( s -> System.out.println("after filter: " + s) )
.mapToDouble(Double::parseDouble)
.reduce(0D,Double::sum);
如果您使用 java 11,您可以在过滤器中使用 String.isBlank()
而不是 isEmpty()。 isEmpty()
查看字符串的长度。 isBlank 查找空格。
带有空格的字符串,技术上不为空,导致引发异常并显示消息 "empty string"。正如另一位发帖者指出的那样,解决方案是先 trim 输入字符串。
这种混淆是 sun.misc.FloatingDecimal.readJavaFormatString
中一个不幸的文档错误的结果,该错误被 Double.parseDouble
间接调用。虽然 String#empty
的语义是
Returns true
if, and only if, length()
is 0.
readJavaFormatString
的实现实际上是trims输入字符串先,然后计算长度,并抛出带有(非常误导的)消息 "empty string":
的 NumberFormatException
in = in.trim(); // don't fool around with white space.
// throws NullPointerException if null
int len = in.length();
if ( len == 0 ) {
throw new NumberFormatException("empty String");
}
这可以通过执行很容易地观察到:
Double.parseDouble(" ");
您可以使用 Apache 的 StringUtils.isNotBlank 函数,因为 well.It 会同时处理 Null 和 Empty 字符串.
double myTotal= Stream.of("","10.00","20.22"," ")
//.map(myObject::getAmount)
.peek( s -> System.out.println("before filter: " + s) )
.filter(StringUtils::isNotBlank)
.peek( s -> System.out.println("after filter: " + s) )
.mapToDouble(Double::parseDouble)
.reduce(0D,Double::sum);
输出:
过滤前:
过滤前:10.00
筛选后:10.00
过滤前:20.22
过滤后:20.22
过滤前:
30.22
我有一个流操作 (Java 8),旨在将一堆字符串解析为双精度数并求和。有些字符串是空的,但我不相信任何字符串都是空的。我已经添加了一个 filter
操作来在空的到达 Double.parseDouble()
之前过滤掉它们可能会导致错误,但过滤器似乎不起作用。
我的代码:
double myTotal= myObjectList.stream()
.map(myObject::getAmount)
.peek( s -> System.out.println("before filter: " + s) )
.filter( s -> !s.isEmpty() )
.peek( s -> System.out.println("after filter: " + s) )
.mapToDouble(Double::parseDouble)
.reduce(0D,Double::sum);
这是在 JSP 中,JSP 编译失败。根据错误页面,异常发生在最后一行 (.reduce(0D,Double::sum);
),但是 "root cause" 是一个“java.lang.NumberFormatException: empty String
” -- Double.parseDouble()
is encountering empty strings.
我尝试了几种 filter
操作的排列组合,包括一些检查 null 和一些检查 !s.equals("")
等。我添加了用于调试的 peek
操作,很明显 before 和 after [=12] 都打印了一个空字符串=]行。
我做错了什么?有没有更好的方法来过滤掉无法解析为双精度的值?
可能是空格,你可以先trim()
字符串,然后检查它是否为空,同时删除空格字符串,如:
double myTotal= myObjectList.stream()
.map(myObject::getAmount)
.peek( s -> System.out.println("before filter: " + s) )
.filter( s -> !s.trim().isEmpty() )
.peek( s -> System.out.println("after filter: " + s) )
.mapToDouble(Double::parseDouble)
.reduce(0D,Double::sum);
如果您使用 java 11,您可以在过滤器中使用 String.isBlank()
而不是 isEmpty()。 isEmpty()
查看字符串的长度。 isBlank 查找空格。
带有空格的字符串,技术上不为空,导致引发异常并显示消息 "empty string"。正如另一位发帖者指出的那样,解决方案是先 trim 输入字符串。
这种混淆是 sun.misc.FloatingDecimal.readJavaFormatString
中一个不幸的文档错误的结果,该错误被 Double.parseDouble
间接调用。虽然 String#empty
的语义是
Returns
true
if, and only if,length()
is 0.
readJavaFormatString
的实现实际上是trims输入字符串先,然后计算长度,并抛出带有(非常误导的)消息 "empty string":
NumberFormatException
in = in.trim(); // don't fool around with white space.
// throws NullPointerException if null
int len = in.length();
if ( len == 0 ) {
throw new NumberFormatException("empty String");
}
这可以通过执行很容易地观察到:
Double.parseDouble(" ");
您可以使用 Apache 的 StringUtils.isNotBlank 函数,因为 well.It 会同时处理 Null 和 Empty 字符串.
double myTotal= Stream.of("","10.00","20.22"," ")
//.map(myObject::getAmount)
.peek( s -> System.out.println("before filter: " + s) )
.filter(StringUtils::isNotBlank)
.peek( s -> System.out.println("after filter: " + s) )
.mapToDouble(Double::parseDouble)
.reduce(0D,Double::sum);
输出:
过滤前:
过滤前:10.00
筛选后:10.00
过滤前:20.22
过滤后:20.22
过滤前:
30.22