I am learning the basics of Java and I am exploring Optionals and abstract classes so I came across the following issue,
I have this code
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......");
}
}
I was expecting to see the prints on the console “It is a Dog” followed by 2 “It is not a Dog” Since I’m using the method .isPresent() on optionals,
But I got 1 print and then a NullPointerException:
That’s what I got printed:
Start
it is a Dog
Barking...
Exception in thread "main" java.lang.NullPointerException
at com.example.helloworldeclipse.Animal.main(Animal.java:24)
Shouldn’t isPresent be safe? is there a better way to cast abstract classes to subclasses in situations similar like this?
I don’t get why it’s not working.. What am I doing wrong here?
Thank you in advance for all the answers..
Advertisement
Answer
The problem is that you are assigning null to an Optional reference when the instanceof check fails.
You have at least two options:
Use
Optional.empty()instead ofnullOptional<Dog> dog = animal instanceof Dog ? Optional.of((Dog) animal) : Optional.empty();
Use Optional’s
filterandmapmethods:Optional<Dog> dog = Optional.of(animal) .filter(Dog.class::isInstance) .map(Dog.class::cast);The predicate
Dog.class::isInstancechecks if the given instance, which is the value within theOptional, is an instance ofDog. This isequivalenttoinstanceof. ThenDog.class::castcasts the given object to aDoginstance.
Note: If animal itself could be null, then you should use Optional::ofNullable instead of Optional::of.