在Java 8中使用实例方法::与空对象的方法引用

4
为什么使用方法引用(::)时,如果将对象实例设为null,则不会抛出NullPointerException?这个问题与IT技术有关。
  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?


2
你将变量 predicateSample 设置为 null。你认为为什么会出现 NPE? - Flown
Java内部并不使用该引用来调用实例方法? - SEY_91
3
你之前的谓词示例(在其为null之前)的引用已经存储在谓词中。 - mlecz
1
在方法引用创建期间,对象引用被解析。创建的lambda表达式指向PredicateSample对象。然后您将变量设置为null,这是一个独立的操作。 - Flown
3个回答

8

语言规范 中的关键行是讨论方法引用的运行时评估(强调是我的):

  • 如果形式为 ExpressionName :: [TypeArguments] Identifier 或 Primary :: [TypeArguments] Identifier ...

    • ....
    • 目标引用是 ExpressionName 或 Primary 的值,在方法引用表达式被评估时确定。

因此,改变目标引用的值之后并不重要。


4
该方法引用“记住”了在初始化时的 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);

1
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);

在上面的代码中,您正在使用null初始化 predicateSample ,然后没有使用此对象 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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接