为什么在方法引用(::
)中使用实例方法时,如果我们将Object实例设置为null,则不会抛出NullPointerException
?
public class MethodReferenceTest {
public static void main(String...strings){
PredicateSample predicateSample = new PredicateSample();
Predicate<String> predicate = predicateSample::isNotEmpty;
// NullpointerException ???
predicateSample = null;
Arrays.asList("a","b","c",null)
.stream()
.filter(predicate)
.forEach(System.out::println);
}
static class PredicateSample{
public boolean isNotEmpty(String s){
return ((s!=null) && (!s.isEmpty()));
}
}
}
在构建谓词后似乎没有调用predicateSample
答案 0 :(得分:7)
the language spec中的关键行是讨论方法参考的运行时评估(强调我的):
如果表单是ExpressionName :: [TypeArguments] Identifier或Primary :: [TypeArguments] Identifier ...
- ....
- 目标参考是ExpressionName或Primary的值,在评估方法参考表达式时确定。
因此,如果您之后更改目标参考的值并不重要。
答案 1 :(得分:3)
方法引用“记住”predicateSample
初始化时的状态。它完全引用您之前创建的new PredicateSample()
。
执行了2行后,您有两个对new PredicateSample()
的引用 - predicateSample
和方法引用中的一个“
改变前者对后者没有影响。
让我们做一个有趣的技巧。
这是一个将new PredicateSample()
打包成predicates[0]
:
PredicateSample[] predicates = new PredicateSample[1];
predicates[0] = new PredicateSample();
在lambda中,您使用对predicates[0]
;
Predicate<String> predicate = string -> predicates[0].isNotEmpty(string);
您将predicates[0]
更新为null
并执行相同的操作:
predicates[0] = null;
Stream.of("a","b","c").filter(predicate).forEach(System.out::println);
答案 2 :(得分:0)
PredicateSample predicateSample = new PredicateSample();
Predicate<String> predicate = predicateSample::isNotEmpty; //it will work fine and initializing with false.
// NullpointerException ???
predicateSample = null;
Arrays.asList("a","b","c",null).stream().filter(predicate).forEach(System.out::println);
在上面的代码中,您使用predicateSample
初始化null
,之后没有使用此对象predicateSample
。
写了
Predicate<String> predicate = predicateSample::isNotEmpty;
// NullpointerException ???
predicateSample = null; // null initialize after `isNotEmpty` call. then why Null Pointer will raised ?
现在暂不再使用predicateSample
了。那为什么NPE?
修改代码以抛出NPE。
PredicateSample predicateSample = new PredicateSample()
// NullpointerException ???
predicateSample = null;;
Predicate<String> predicate = predicateSample::isNotEmpty; //it will not work fine and raise NPE.
Arrays.asList("a","b","c",null).stream().filter(predicate).forEach(System.out::println);
答案 3 :(得分:0)
为什么要抛出NullPointerException
?看看代码的这些行:
PredicateSample predicateSample = new PredicateSample();
// You have initialized the predicateSample variable.
// It doesn't contain the null value longer
Predicate<String> predicate = predicateSample::isNotEmpty;
// You have declared the functional interface, which is not null as well
predicateSample = null;
// You have set the predicateSample variable to the null.
// Since the predicate is already declared, this line has no effect to it.
Arrays.asList("a","b","c",null).stream()
.filter(predicate)
.forEach(System.out::println);
// You perform the Stream with the predicate variable,
// which remains unchanged since the initialization
如果您希望在NullPointerException
功能界面使用之前遇到predicateSample = null;
,请先设置predicate
一行。
PredicateSample predicateSample = new PredicateSample();
predicateSample = null;
Predicate<String> predicate = predicateSample::isNotEmpty; // now predicateSample is null, thus the NPE is thrown.
Arrays.asList("a","b","c",null).stream()
.filter(predicate)
.forEach(System.out::println);