-1
votes

Comment déballer correctement un optionnel en Java?

J'apprends les bases de Java et j'explore les Optionals and abstract classes , je suis donc tombé sur le problème suivant,

J'ai ce code

Start
it is a Dog
Barking...
Exception in thread "main" java.lang.NullPointerException
    at com.example.helloworldeclipse.Animal.main(Animal.java:24)

Je m'attendais à voir les impressions sur la console "C'est un chien" suivi de 2 "Ce n'est pas un chien" Puisque j'utilise la méthode .isPresent() sur les options,

Mais j'ai eu 1 impression, puis une NullPointerException :

C'est ce que j'ai imprimé:

import java.util.Optional;

public abstract class Animal {
    abstract void makeSound();
    
    public static void main(String[] args) {
        System.out.println("Start");
        
        Dog dog = new Dog();
        Cat cat = new Cat();
        Horse horse = new Horse();
        
        
        Animal[] animals = {dog, cat, horse};
        
        for (Animal animal : animals) {
            
            Optional<Dog> _dog = animal instanceof Dog ? Optional.of((Dog) animal) : null;
            Optional<Cat> _cat = animal instanceof Cat ? Optional.of((Cat) animal) : null;
            Optional<Horse> _horse = animal instanceof Horse ? Optional.of((Horse) animal) : null;
            
            if (_dog.isPresent()) {
                System.out.println("it is a Dog");
            } else {
                System.out.println("it is NOT a Dog");
            }
                        
            animal.makeSound();
        }
    
    }
}

class Horse extends Animal {
    String speed = "Fast";
    @Override
    void makeSound() {
        System.out.println("Neighing...");
    }
}

class Dog extends Animal {
    String color = "Brown";
    @Override
    void makeSound() {
        System.out.println("Barking...");
    }
}

class Cat extends Animal {
    Integer lives = 9;
    @Override
    void makeSound() {
        System.out.println("Mewoing......");
    }
}

IsPresent ne devrait-il pas être sûr? y a-t-il un meilleur moyen de convertir des classes abstraites en sous-classes dans des situations similaires?

Je ne comprends pas pourquoi cela ne fonctionne pas. Qu'est-ce que je fais de mal ici?

Merci d'avance pour toutes les réponses.


2 commentaires

Vous devez affecter _dog , _cat et _horse à Optional.empty() au lieu de null lorsque le type ne correspond pas.


Une variable / champ / paramètre Optional ne devrait jamais être null , cela anéantirait fondamentalement toute la raison de son existence.


3 Réponses :


0
votes

Vous ne devez pas utiliser null, utilisez à la place Optional<T>.empty() , lisez ici https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#empty--


0 commentaires

0
votes

Le problème est que vous vérifiez si dog.isPresent mais que vous attribuez également potentiellement null à dog lorsque la valeur n'est pas dog. c'est-à-dire sur la deuxième itération.

Optional<Dog> dog = animal instanceof Dog ? Optional.of((Dog) animal) : Optional.empty();


0 commentaires

2
votes

Le problème est que vous attribuez null à une référence Optional lorsque la vérification d' instanceof échoue.

Vous avez au moins deux options:

  1. Utilisez Optional.empty() au lieu de null

    Optional<Dog> dog = Optional.of(animal)
        .filter(Dog.class::isInstance)
        .map(Dog.class::cast);
    
  2. Utilisez les méthodes de filter et de map facultatives:

    Optional<Dog> dog = animal instanceof Dog ? Optional.of((Dog) animal) : Optional.empty();
    

    Le prédicat Dog.class::isInstance vérifie si l'instance donnée, qui est la valeur dans Optional , est une instance de Dog . C'est equivalent à instanceof . Puis Dog.class::cast l'objet donné en une instance Dog .


Remarque: Si animal lui animal même peut être null , alors vous devez utiliser Optional::ofNullable au lieu de Optional::of .


2 commentaires

Je pense que je suis trop habitué à swift) Merci beaucoup, la deuxième option est encore plus compacte et lisible 👍


@Lucas Je suis totalement d'accord avec vous!