Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using instance method in java 8 :: method reference with null Object

Tags:

java

java-8

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?

like image 270
SEY_91 Avatar asked Dec 13 '22 20:12

SEY_91


2 Answers

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.

like image 59
Andy Turner Avatar answered Feb 23 '23 09:02

Andy Turner


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);
like image 32
Andrew Tobilko Avatar answered Feb 23 '23 10:02

Andrew Tobilko