I have been playing a little with lambda statements in Java 8, and am stuck: I don't know why this isn't working.
I want the lambda statement to return the array where the sum of the first element, multiplied with the second element, is the highest, in this case {2,3}.
Any help is appreciated.
public static void main(String[] args)
{
//Test data
final TreeSet<Integer[]> test = new TreeSet<Integer[]>();
test.add( new Integer[]{1,2} );
test.add( new Integer[]{1,3} );
test.add( new Integer[]{1,4} );
test.add( new Integer[]{2,1} );
test.add( new Integer[]{2,2} );
test.add( new Integer[]{2,3} );
Integer[] test1 = test.stream()
.min((Integer[] l , Integer[] r) -> { return Integer.compare( l[0] * l[1] , r[0] * r[1] ); })
.get(); //Run-time error: java.lang.ClassCastException: [Ljava.lang.Integer; cannot be cast to java.lang.Comparable
Integer[] test2 = test.stream()
.min((Integer[] l , Integer[] r) -> { return Integer.valueOf( l[0] * l[1] ).compareTo( r[0] * r[1] ); })
.get(); //Run-time error: java.lang.ClassCastException: [Ljava.lang.Integer; cannot be cast to java.lang.Comparable
}
Thanks,
-PStiger
The problem is when you put the elements in the tree set. If you don't provide explicitly a comparator, it assumes that the elements it contains have a natural order (so they implement the comparable interface). This is not the case for arrays.
This is what the documentation states about the no-args constructor you are using:
Constructs a new, empty tree set, sorted according to the natural ordering of its elements. All elements inserted into the set must implement the Comparable interface.
The stacktrace clearly indicates that the exception is thrown at the line where you add the first array instance (and not when the code in the stream pipeline is executed because you never get to this point).
You can even browse the source. A TreeSet<E> is using a TreeMap<E, Object> internally to store the elements. When you call add, it calls m.put(e, PRESENT).
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
Since there is no elements (the root is null), it calls compare(key, key) (where key is the integer array). This method compare is a utility method:
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
}
As you didn't provide a comparator, it tries to cast the key as a comparable, hence the ClassCastException.
To fix that you need to provide a comparator. Here's one that compares the arrays by their first element:
final TreeSet<Integer[]> test = new TreeSet<>(Comparator.comparing(a -> a[0]));
.min((l , r) -> Integer.compare( l[0] * l[1] , r[0] * r[1]))
or even better:
.min(Comparator.comparing(a -> a[0] * a[1]))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With