Maison  >  Article  >  Java  >  Comment éviter l'exception de pointeur nul en Java

Comment éviter l'exception de pointeur nul en Java

高洛峰
高洛峰original
2017-01-18 14:42:311691parcourir

Personne n’aime NullPointerException ! Existe-t-il un moyen de les éviter ? Peut être. .

Cet article abordera les technologies suivantes

1. Type facultatif (nouvellement introduit dans Java 8)
2 Classe Objects (originale dans Java 7)

Facultatif. classe en Java 8

Qu'est-ce que c'est ?

1. Un type nouvellement introduit dans Java 8
2 Il est utilisé comme wrapper pour un objet d'un type spécifié ou pour des scénarios où aucun objet (null) n'existe

Simplement. en d'autres termes, c'est une meilleure alternative pour gérer les valeurs nulles (attention : cela n'est peut-être pas si évident à première vue)

Utilisation de base

C'est un type (une classe) - Donc , comment créer une instance de ce type ?

Utilisez simplement ses trois méthodes statiques :

public static Optional<String> stringOptional(String input) {
    return Optional.of(input);
}

Simple et clair - créez une instance contenant cette valeur Wrapper facultatif. N'oubliez pas : si cette valeur est nulle, elle lancera NPE !

public static Optional<String> stringNullableOptional(String input) {
if (!new Random().nextBoolean()) {
input = null;
}
return Optional.ofNullable(input);
}

Je pense personnellement que c'est mieux. De cette façon, il n'y aura aucun risque de NPE - si l'entrée est nulle, un Facultatif

public static Optional<String> emptyOptional() {
return Optional.empty();
}

vide sera renvoyé si vous voulez vraiment renvoyer une valeur "vide". Une valeur « vide » ne signifie pas null.

Bien, alors comment consommer/utiliser Facultatif ?

public static void consumingOptional() {
Optional<String> wrapped = Optional.of("aString");
if (wrapped.isPresent()) {
System.out.println("Got string - " + wrapped.get());
}
else {
System.out.println("Gotcha !");
}
}

Le moyen le plus simple est de vérifier si le wrapper facultatif a réellement une valeur (en utilisant la méthode isPresent) - vous vous demanderez quel est l'avantage par rapport à l'utilisation de if(myObj != null). Ne vous inquiétez pas, je vais vous expliquer cela clairement.

public static void consumingNullableOptional() {
String input = null;
if (new Random().nextBoolean()) {
input = "iCanBeNull";
}
Optional<String> wrapped = Optional.ofNullable(input);
System.out.println(wrapped.orElse("default"));
}

Vous pouvez utiliser la méthode orElse, de sorte que si la valeur encapsulée est effectivement une valeur nulle, vous pouvez l'utiliser pour renvoyer une valeur par défaut - ses avantages sont évidents. Lors de l'extraction de la valeur réelle, vous pouvez éviter la méthode évidemment redondante consistant à appeler la méthode ifPresent.

public static void consumingEmptyOptional() {
String input = null;
if (new Random().nextBoolean()) {
input = "iCanBeNull";
}
Optional<String> wrapped = Optional.ofNullable(input);
System.out.println(wrapped.orElseGet(
() -> {
return "defaultBySupplier";
}
 
));
}

Je suis un peu confus à ce sujet. Pourquoi existe-t-il deux méthodes différentes pour le même objectif ? orElse et orElseGet peuvent évidemment être surchargés (avec le même nom mais des paramètres différents).

Quoi qu'il en soit, la différence évidente entre ces deux méthodes réside dans leurs paramètres - vous pouvez choisir d'utiliser des expressions lambda au lieu d'instances de Fournisseur pour accomplir cela (une interface fonctionnelle)

Pourquoi utiliser Facultatif est-il préférable que le contrôle nul commun ?

1. Le plus grand avantage de l'utilisation de Optionnel est que vous pouvez exprimer votre intention plus clairement - renvoyer une valeur nulle rendra les consommateurs confus (lorsque NPE se produit) si cela est renvoyé intentionnellement, vous devez donc vérifier le javadoc pour un positionnement ultérieur. L’utilisation de Facultatif est assez simple.

2. Avec Optionnel, vous pouvez complètement éviter le NPE - comme mentionné ci-dessus, l'utilisation de Option.ofNullable, orElse et orElseGet peut nous éloigner du NPE.

Un autre sauveur !

Regardez cet extrait de code

package com.abhirockzz.wordpress.npesaviors;
 
import java.util.Map;
import java.util.Objects;
 
public class UsingObjects {
 
String getVal(Map<String, String> aMap, String key) {
return aMap.containsKey(key) ? aMap.get(key) : null;
}
 
public static void main(String[] args) {
UsingObjects obj = new UsingObjects();
obj.getVal(null, "dummy");
}
}

Lequel pourrait être vide ?

1.Objet Map
2.La clé utilisée pour la recherche
3.L'instance de l'appel de méthode

Si un NPE est lancé, comment pouvons-nous déterminer lequel il est nul ?

package com.abhirockzz.wordpress.npesaviors;
 
import java.util.Map;
import java.util.Objects;
 
public class UsingObjects {
String getValSafe(Map<String, String> aMap, String key) {
Map<String, String> safeMap = Objects.requireNonNull(aMap,
"Map is null");
String safeKey = Objects.requireNonNull(key, "Key is null");
 
return safeMap.containsKey(safeKey) ? safeMap.get(safeKey) : null;
}
 
public static void main(String[] args) {
UsingObjects obj = new UsingObjects();
obj.getValSafe(null, "dummy");
}
}

Méthode requireNonNull

1 Si l'objet n'est pas nul, retourne lui-même
2 Si la valeur est nulle, le NPE renvoyé aura le message spécifié

.

Pourquoi est-ce mieux que if(myObj!=null) ?

Les informations de trace de pile que vous voyez verront clairement l'appel de méthode de Objects.requireNonNull. Ceci, combiné à votre propre journal d’erreurs, peut vous permettre de localiser le problème plus rapidement. . . Au moins, c'est plus rapide à mon avis.

Vous pouvez également personnaliser votre propre validateur, par exemple, implémenter un validateur simple pour vous assurer qu'il n'y a pas de valeurs nulles.

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
 
public class RandomGist {
 
    public static <T> T requireNonEmpty(T object, Predicate<T> predicate, String msgToCaller){
        Objects.requireNonNull(object);
        Objects.requireNonNull(predicate);
        if (predicate.test(object)){
            throw new IllegalArgumentException(msgToCaller);
        }
        return object;
    }
 
    public static void main(String[] args) {
        
    //Usage 1: an empty string (intentional)
 
    String s = "";
    System.out.println(requireNonEmpty(Objects.requireNonNull(s), (s1) -> s1.isEmpty() , "My String is Empty!"));
 
    //Usage 2: an empty List (intentional)
    List list =  Collections.emptyList();
    System.out.println(requireNonEmpty(Objects.requireNonNull(list), (l) -> l.isEmpty(), "List is Empty!").size());
 
    //Usage 3: an empty User (intentional)
    User user = new User("");
    System.out.println(requireNonEmpty(Objects.requireNonNull(user), (u) -> u.getName().isEmpty(), "User is Empty!"));
}
 
    private static class User {
        private String name;
 
        public User(String name){
            this.name = name;
        }
 
        public String getName(){
            return name;
        }
    }
}

Ne laissez pas les NPE devenir pénibles au mauvais endroit. Nous disposons de nombreux outils pour mieux lutter contre les NPE et même les éradiquer complètement !

Pour plus d'articles sur la façon d'éviter les exceptions de pointeur nul en Java, veuillez faire attention au site Web PHP chinois !


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn