2017-10-04 3 views
3

Pourquoi lors de l'utilisation d'une méthode d'instance dans la référence de méthode (::) ne lance pas NullPointerException si nous définissons l'instance Object sur null?Utilisation de la méthode d'instance dans java 8 :: reference de méthode avec null Objet

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

Il semble que predicateSample ne puisse être retenue après la construction du prédicats?

+2

Vous définissez la variable 'predicateSample' à' null'. Pourquoi pensez-vous qu'il devrait y avoir un NPE? – Flown

+0

En interne java n'utilise pas cette référence pour appeler la méthode d'instance? –

+3

La référence à votre ancien prédicatSample (avant qu'elle ne soit nulle) est déjà stockée dans le prédicat – mlecz

Répondre

7

La ligne clé dans the language spec est où il discute de l'évaluation de l'exécution des références de méthode (mine d'importance):

  • Si le formulaire est ExpressionName :: [TypeArguments] Identificateur ou Primary :: [TypeArguments] Identificateur ...

    • ....
    • La référence cible est la valeur de ExpressionName ou primaire, tel que déterminé lorsque l'expression de référence de la méthode a été évaluée.

Il n'a pas d'importance si vous modifiez la valeur de la référence cible après.

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

dans le code ci-dessus vous initialisez predicateSample avec null et par la suite il n'y a pas d'utilisation de cet objet predicateSample.

dans votre code que vous avez écrire

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

maintenant aucune utilisation de predicateSample plus loin. alors pourquoi NPE?

Code modifié pour lancer 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); 
0

Pourquoi devrait jeter le NullPointerException? Jetez un coup d'oeil sur ces lignes de votre code:

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 

Si vous souhaitez rencontrer l'NullPointerException, définissez predicateSample = null; une ligne plus tôt - à droite avant de l'utiliser pour l'interface fonctionnelle 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); 
3

La référence de la méthode «se souvient » l'état de l'predicateSample quand il a été initialisé. Il a une référence exacte à celle new PredicateSample() que vous avez créée auparavant.

Après 2 lignes exécutées, vous avez deux références à ce new PredicateSample() - le predicateSample et le "dans" la référence de la méthode.

Changer le premier n'a aucun effet sur ce dernier.


Faisons un tour intéressant.

Voici un tableau pour envelopper un new PredicateSample() dans un predicates[0]:

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

Dans le lambda, vous utilisez une référence à la predicates[0];

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

Vous mettez à jour le predicates[0] à null et faire la même chose:

predicates[0] = null; 
Stream.of("a","b","c").filter(predicate).forEach(System.out::println);