Reputation: 105
Getting java.lang.ClassCastException when stream.filter returns multiple resullts
package lambda;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaDemo {
public static void main(String[] args) {
List<Student> stList = new LinkedList<Student>();
stList.add(new Student("Ankit", 22));
stList.add(new Student("Soham", 32));
stList.add(new Student("Nitin", 42));
stList.add(new Student("Xoxo", 55));
stList.add(new Student("Chetan", 62));
Department scrDept = new Department("Science");
scrDept.getStList().add(new Student("Ankit", 22));
scrDept.getStList().add(new Student("Soham", 52));
Department artDept = new Department("Arts");
artDept.getStList().add(new Student("Xoxo", 42));
artDept.getStList().add(new Student("Chetan", 92));
List<Department> deptList = new ArrayList<Department>();
deptList.add(scrDept);
deptList.add(artDept);
deptList.stream().flatMap(dept -> dept.getStList().stream())
.forEach(employee -> System.out.println(employee.getName()));
List<Student> orderedPassedStd = deptList.stream().flatMap(dept -> dept.getStList().stream())
.filter(student -> student.getName().length() >= 4).sorted().collect(Collectors.toList());
for (Student std : orderedPassedStd) {
System.out.println(std.getName() + " --------- " + std.getMarks());
}
}
}
class Department {
String deptName;
List<Student> stList = new ArrayList<Student>();
public Department(String deptName) {
this.deptName = deptName;
}
public Department(String deptName, List<Student> stList) {
this.deptName = deptName;
this.stList = stList;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<Student> getStList() {
return stList;
}
public void setStList(List<Student> stList) {
this.stList = stList;
}
}
class Student {
String name;
float marks;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMarks() {
return marks;
}
public void setMarks(float marks) {
this.marks = marks;
}
public Student(String name, float marks) {
this.name = name;
this.marks = marks;
}
}
Output : Ankit Soham Xoxo Chetan Exception in thread "main" java.lang.ClassCastException: class lambda.Student cannot be cast to class java.lang.Comparable (lambda.Student is in module javaMasterClass 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:1515) at java.base/java.util.ArrayList.sort(ArrayList.java:1750) at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392) at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at javaMasterClass/lambda.LambdaDemo.main(LambdaDemo.java:34)
Upvotes: 0
Views: 826
Reputation: 11
sorted() method doc: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#sorted--
It says that when an element is not Comparable that ClassCastException exception will be thrown.
You need to either make Student implement Comparable interface and implement method compareTo like this
class Student implements Comparable<Student>{
String name;
float marks;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMarks() {
return marks;
}
public void setMarks(float marks) {
this.marks = marks;
}
public Student(String name, float marks) {
this.name = name;
this.marks = marks;
}
@Override
public int compareTo(Student o) {
var cmp = Float.compare(this.marks, o.marks);
if(cmp != 0) return cmp;
//TODO add this.name == null logic depending on needs
return this.name.compareTo(o.name);
//OR a one liner
//return Comparator.comparing(Student::getMarks).thenComparing(Student::getName).compare(this, o);
}
}
You can add any logic for comparing based on your needs. The convention is if this is > than o then compareTo returns integer > than 0, if they are equal 0 is returned, and if this is < than 0 , negative integer is returned. ( https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html )
Or you can call sorted with comparator argument
Comparator.comparing(Student::getMarks).thenComparing(Student::getName)
(once again you can put some other logic in here)
Upvotes: 1
Reputation: 796
At the place, where you're trying to sort the students, based on your sorting need, you can provide a comparator in the following way:
Update the line which contains .sorted()
to,
If you want to sort Students based on Name,
.sorted(Comparator.comparing(Student::getName))
or
.sorted((s1, s2) -> s1.getName().compareTo(s2.getName()))
If you want to sort Students based on Marks,
.sorted(Comparator.comparing(Student::getMarks))
or
.sorted((s1, s2) -> Float.compare(s1.getMarks(), s2.getMarks()))
If you want to descending sorting on Student's Marks,
.sorted(Comparator.comparing(Student::getMarks).reversed())
Upvotes: 2