Home > Software design >  How to map an instance of type Object to specific Class in Java using Stream API
How to map an instance of type Object to specific Class in Java using Stream API

Time:04-25

I've encountered the following problem:

If I map an object in a stream to a specific class in Java, the java stream API does not recognize a specific object after the mapping and still assumes it is an object. What am I doing wrong, and is there a way to solve this without potential class cast exceptions?

Here is the code example:

public class MyMapper {

        MyMapper() {
            Object someObject = new Person();
            final var listOfObjects = List.of(someObject);
            final var listOfPerson = toListOfPerson(listOfObjects);
        }

        List<Optional<Person>> toListOfPerson(Object object) {
            return ((List) object).stream()
                           .map(this::toPerson)
                           .collect(Collectors.toList());
        }

        Optional<Person> toPerson(Object object) {

            if (object instanceof Person) {
                return Optional.of((Person) object);
            }
            return Optional.empty();
        }

        public class Person {}
}

CodePudding user response:

cast it to a typed List and then your .map(this::toPerson) will "accept" the element of this List

List<Optional<Person>> toListOfPerson(Object object) {
            return ((List<Object>) object).stream()
                    .map(this::toPerson)
                    .collect(Collectors.toList());
    }

CodePudding user response:

It doesn't make sense to keep the collection of optional objects which could be potentially empty, it almost the same as storing null values.

If you think for some reason that List<Optional<Person>> is good idea, I recommend you to have a look at this question. A quote from the answer by Stuart Marks (JDK developer):

I'm sure somebody could come up with some contrived cases where they really want to store an Optional in a field or a collection, but in general, it is best to avoid doing this.

Optional was introduced in the JDK as a limited mechanism to represent a nullable return value. That is its only purpose, other cases of usage of optional objects like optional method arguments, fields, collections of optionals are considered to be antipattern.

You have to unpack your Optionals in the stream:

public List<Person> toListOfPerson(Object object) {
    if (!(object instanceof List<?>)) {
        return Collections.emptyList();
    }
    
    return ((List<?>) object).stream()
        .map(this::toPerson)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(Collectors.toList());
}
  • Related