4

Why when using an instance method in method reference (::) does not throw a NullPointerException if we set the Object instance to null?

  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()));
            }
        }
    }

It seems like predicateSample is not invoked after constructing the Predicate?

Leonardo Pina
  • 458
  • 1
  • 7
  • 17
SEY_91
  • 1,615
  • 15
  • 26
  • 2
    You're setting the variable `predicateSample` to `null`. Why do you think there should be a NPE? – Flown Oct 04 '17 at 12:04
  • Internally java is not using this reference to invoke the instance method?? – SEY_91 Oct 04 '17 at 12:06
  • 3
    reference to your old predicateSample (before it was null) is already stored in predicate – mlecz Oct 04 '17 at 12:09
  • 1
    During the method reference creation the object reference is resolved. And the created lambda expression is pointing to the `PredicateSample` object. Then you set the variable to `null` which is an independent operation. – Flown Oct 04 '17 at 12:10
  • See also [What is the equivalent lambda expression for System.out::println](https://stackoverflow.com/a/28025717/2711488)… – Holger Oct 04 '17 at 14:37

3 Answers3

8

The key line in the language spec is where it is discussing the runtime evaluation of method references (emphasis mine):

  • If the form is ExpressionName :: [TypeArguments] Identifier or Primary :: [TypeArguments] Identifier ...

    • ....
    • The target reference is the value of ExpressionName or Primary, as determined when the method reference expression was evaluated.

So it doesn't matter if you change the value of the target reference afterwards.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
4

The method reference "remembered" the state of the predicateSample when it was initialized. It has a reference exactly to that new PredicateSample() you have created before.

After 2 lines executed, you have got two references to that new PredicateSample() - the predicateSample and the one "within" the method reference.

Changing the former makes no effect to the latter.


Let's do an interesting trick.

Here is an array to wrap up a new PredicateSample() into a predicates[0]:

PredicateSample[] predicates = new PredicateSample[1];
predicates[0] = new PredicateSample();

Within the lambda, you use a reference to the predicates[0];

Predicate<String> predicate = string -> predicates[0].isNotEmpty(string);

You update the predicates[0] to null and do the same stuff:

predicates[0] = null;
Stream.of("a","b","c").filter(predicate).forEach(System.out::println);
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
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);

in above code you are initializing predicateSample with null and thereafter there is no use of this object predicateSample.

in your code you have write

Predicate<String> predicate = predicateSample::isNotEmpty;
            // NullpointerException ???
predicateSample = null; // null initialize after `isNotEmpty` call. then why Null Pointer will raised ?

now no use of predicateSample further. then why NPE?

Modified code to throw 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);
Vikrant Kashyap
  • 6,398
  • 3
  • 32
  • 52