使用java 8中的instance方法:使用null Object的方法引用

时间:2017-10-04 12:02:20

标签: java java-8

为什么在方法引用(::)中使用实例方法时,如果我们将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

4 个答案:

答案 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);