如何正确解包 Java 中的可选值?

How to properly unwrap an optional in Java?

我正在学习 Java 的基础知识并且正在探索 Optionals and abstract classes 所以我遇到了以下问题,

我有这个代码

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......");
    }
}

我期待在控制台上看到“It is a Dog”后面跟着 2 个“It is not a Dog”的打印,因为我在选项上使用方法 .isPresent()

但我打印了 1 张,然后是 NullPointerException:

这就是我打印的内容:

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

isPresent 不应该是安全的吗?在类似这样的情况下,是否有更好的方法将 abstract 类 转换为 sub类?

我不明白为什么它不起作用..我做错了什么?

预先感谢您的所有回答..

您不应使用 null,请改用 Optional<T>.empty(),请阅读此处 https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#empty--

问题是您正在检查 dog.isPresent 但当值不是 dog 时,您也可能将 null 分配给 dog。即在第二次迭代中。

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

问题是当 instanceof 检查失败时,您将 null 分配给 Optional 引用。

您至少有两个选择:

  1. 使用Optional.empty()代替null

    Optional<Dog> dog = animal instanceof Dog ? Optional.of((Dog) animal) : Optional.empty();
    
  2. 使用 Optional 的 filter and map 方法:

    Optional<Dog> dog = Optional.of(animal)
        .filter(Dog.class::isInstance)
        .map(Dog.class::cast);
    

    谓词 Dog.class::isInstance 检查给定实例(即 Optional 中的值)是否是 Dog 的实例。这是 equivalentinstanceof。然后 Dog.class::cast 将给定对象转换为 Dog 实例。


注意:如果animal本身可以是null,那么你应该使用Optional::ofNullable instead of Optional::of.