2

I'm iterating all Student data using natural sorting method of java 8 sorted(). While iterating student data, get exception in IDE console class com.java8.Student cannot be cast to class java.lang.Comparable. My StreamStudent.java file is inside com.java8 package.

Here is my full stack trace:

Exception in thread "main" java.lang.ClassCastException: class com.java8.Student cannot be cast to class java.lang.Comparable (com.java8.Student is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
    at java.base/java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47)
    at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
    at java.base/java.util.TimSort.sort(TimSort.java:220)
    at java.base/java.util.Arrays.sort(Arrays.java:1307)
    at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:353)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at com.java8.StreamStudent.main(StreamStudent.java:72)

Here down is my code:

package com.java8;

import java.util.*;
import java.util.stream.*;

class Student{
    String firstName;
    String lastName;
    Integer groupId;
    Integer age;

    // constructor and getter, setter

}

public class StreamStudent {
    public static void main(String[] args) {
        List<Student> stdList = new ArrayList<>();
        stdList.add(new Student("Sara", "Mills", 1, 18));
        stdList.add(new Student("Andrew", "Gibson", 2, 21));
        stdList.add(new Student("Craig", "Ellis", 1, 23));
        stdList.add(new Student("Steven", "Cole", 2, 19));
        stdList.add(new Student("Andrew", "Carter", 2, 2));

        
        System.out.println("1. Sort all student firstname by name");
        List<Student> students =  stdList.stream().sorted().collect(Collectors.toList());
        students.forEach((s) -> System.out.println(s.getFirstName() + " " + s.getLastName() + " " + s.getGroupId() + " " + s.getAge()));
    }
}
2
  • 3
    Since there are different options how to sort a list of students (by name, by age, etc) and none of them is an obvious natural order for students, it’s more straight-forward to use a comparator, e.g. sorted(Comparator.comparingInt(Student::getAge)) or sorted(Comparator.comparing(Student::getLastName, String.CASE_INSENSITIVE_ORDER)), rather than implementing Comparable. As a side note, you can sort an ArrayList directly, e.g. stdList.sort(Comparator.comparing(Student::getFirstName)); without streaming/ collecting into a new list. Commented Jun 14, 2022 at 7:29
  • 2
    "Why ...?"--> "natural sorting method" --> elements must have a natural order --> elements must implement Comparable. From documentation: "If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown ..." Commented Jun 14, 2022 at 7:59

4 Answers 4

7

Student must implement Comparable. The implementation of Comparable is what defines the natural ordering.

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

public class Student implements Comparable<Student> {

  @Override
  public int compareTo(Student o) {
    //implement comparison here
    return 0;
  }
}
Sign up to request clarification or add additional context in comments.

Comments

3

The elements of your stream must implement the Comparable interface in order to be sorted via the sorted() stream operation. Alternatively, if you cannot change the implementation of the Student class, you can supply a Comparator instance to the overloaded version sorted(Comparator<? super T> comparator). This way you can still sort your elements without having to change the Student's implementation.

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#sorted-java.util.Comparator-

Student Implementing Comparable

class Student implements Comparable<Student> {
    String firstName;
    String lastName;
    Integer groupId;
    Integer age;

    // constructor and getter, setter

    @Override
    public int compareTo(Student o) {
        return Comparator.comparing(Student::getFirstName).thenComparing(Student::getLastName).compare(this, o);
    }
}

public class StreamStudent {
    public static void main(String[] args) {
        // ... same code of yours ...

        List<Student> students =  stdList.stream().sorted().collect(Collectors.toList());

        // ... same code of yours ...
    }
}

Supply a Comparator to sorted

public class StreamStudent {
    public static void main(String[] args) {
        // ... same code of yours ...

        List<Student> students =  stdList.stream().sorted(Comparator.comparing(Student::getFirstName).thenComparing(Student::getLastName)).collect(Collectors.toList());

        // ... same code of yours ...
    }
}     

Comments

1

Your student class should implement Comparable interface so it can be sorted:

class Student implements Comparable<Student> {
    String firstName;
    String lastName;
    Integer groupId;
    Integer age;

    @Override
    public int compareTo(Student o) {
        return this.firstName.compareTo(o.firstName);

        //In case you want compare based on multiple fields
        /*
        return Comparator
              .comparing((Student s)->s.lastName)
              .thenComparing(s->s.firstName)
              .compare(this, o);
       */
    }
}

Another solution is implementing Comparator interface for class and passing it as input to sorted method, This is useful in cases that you want sort bases on different fields in different sitations:

Comparator<Student> studentComparator
        = Comparator.comparing(Student::getLastName).thenComparing(Student::getFirstName);

List<Student> studentsSorted =  stdList.stream().sorted(studentComparator).collect(Collectors.toList());

Comments

0

You need to implement Comparable. Here a link that might help you. You have to implement the method compareTo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.