Developer
Developer

Reputation: 533

lambda expression ClassCastException in Java

I am trying to learn streaming in java 8. Following is my code :

Main.java

public class Main {
    public static void main(String[] args) {

        Person person = new Person("FirstName", "LastName");
        List<Person> personList = new ArrayList<>();
        personList.add(person);

        Place place = new Place("name", "country");
        List<Place> placeList = new ArrayList<>();
        placeList.add(place);


        List<List<Object>> objects = new ArrayList<>();
        objects.add(Collections.singletonList(personList));
        objects.add(Collections.singletonList(placeList));

        List<Object> persons = objects.get(0);
        List<String> firstNames = persons.stream()
                .map(o -> ((Person)o).getFirstName())
                .collect(Collectors.toList());

        firstNames.forEach(System.out::println);
    }
}

Person.java

@Data
public class Person {
    String firstName;
    String lastName;

    public Person(String firstName, String lastName) {
        setFirstName(firstName);
        setLastName(lastName);
    }
}

Place.java

@Data
public class Place {
    String name;
    String country;

    public Place(String name, String country) {
        setName(name);
        setCountry(country);
    }
}

Exception :

Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to Person
    at Main.lambda$main$0(Main.java:28)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.Collections$2.tryAdvance(Collections.java:4717)
    at java.util.Collections$2.forEachRemaining(Collections.java:4725)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at Main.main(Main.java:29)

I have List of List which is holding Object (I am using Object since I want to use a different type of object to be stored into the collection). I am storing the collection of Person and collection of Place into this List of List collection.

Inside the streaming, I am trying to get the only firstName of all the persons. However, when I use lamba expression which goes through each element and get the firstName does not work with casting.

Question:

  1. Am I doing anything wrong?
  2. Is there any other way(other than map in streaming) to get all the FirstName of the Person Object with stream API?

Upvotes: 2

Views: 6820

Answers (1)

SwiftMango
SwiftMango

Reputation: 15284

personList is a List of Person

Collections.singletonList(personList) is a List of List of Person

objects is a List of List of List of Person/Place.

    List<Object> persons = objects.get(0);   // persons is a List of List of Person
    List<String> firstNames = persons.stream()  
    //each element in the stream is a List of Person, so you cannot cast it to Person.
            .map(o -> ((Person)o).getFirstName())
            .collect(Collectors.toList());

You can either remove the singletonList function so that you reduce a level of list:

    List<List<?>> objects = new ArrayList<>();
    objects.add(personList);
    objects.add(placeList);

or go deeper one list when you do map:

    List<String> firstNames = persons.stream() 
            //Because persons is declared as List of Objects, so you need to cast each element into a List before calling get 
            .map(o -> ((Person)((List)o).get(0))).getFirstName())
            .collect(Collectors.toList());

Upvotes: 6

Related Questions