Why is Streams.allMatch(in Java8) trying to evaluate all the expressions even if the value can be determined midway?

孤街浪徒 提交于 2020-04-06 18:42:58

问题


Consider this snippet -

 String a = "hello" , b = null, c = "guru";
  boolean value = Stream
  .of(a, b, b.substring(2),c)
  .allMatch(x -> x != null);

  System.out.println(value);

This results in NPE. It seems to be doing b.substring(2) and since b is null, NPE is thrown. Why is this condition evaluated? The second expression b is null and hence evaluates to false. So, allMatch will be false regardless of the truth values of the subsequent operations. In that case, why is it trying to evaluate b.substring(2)?

This article and this article claim that it may not evaluate all the expressions if not necessary for determining the result. That clearly does not seem to be the case here.


Prior to Java 7 -

if(b != null && b.substring(2) != null)

this would not throw NPE because b!= null is false and it would return false there itself. So, can we say that Streams.allMatch is not an exact equivalent of the above Java code snippet?



回答1:


Streams.allMatch is not an exact equivalent of the above Java code snippet?

Of course it is not! Streams are very new way of thinking the processing of data.

Anyway your problem is (not related to this) just that for any function call, arguments are evaluated, thus the call to of necessitate the evaluation of b.subString(2) which obviously throw a NPE.

Related info from the Java Language Specification (emphasize is mine):

15.7.4 Argument Lists are Evaluated Left-to-Right

In a method or constructor invocation or class instance creation expression, argument expressions may appear within the parentheses, separated by commas. Each argument expression appears to be fully evaluated before any part of any argument expression to its right.




回答2:


This has nothing to do with the allMatch, and everything to do with the fact that all arguments to a method get evaluated before that method is called, under all circumstances. All arguments to Stream.of, in this particular case, get evaluated before Stream.of is called.

If you really wanted something different, the closest thing to the behavior you want would look like

Stream
  .<Supplier<String>>of(() -> a, () -> b, () -> b.substring(2), () -> c)
  .map(Supplier::get)
  .allMatch(x -> x != null)


来源:https://stackoverflow.com/questions/60641257/why-is-streams-allmatchin-java8-trying-to-evaluate-all-the-expressions-even-if

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!