Java comparator issue when passed to Collections.sort - java

When testing with less load in local it worked fine.
private static class CoordinateComparator implements Comparator<Coordinate> {
#Override
public int compare(Coordinate o1, Coordinate o2) {
return o1.x <= o2.x ? -1 : 1;
}
}
Here x is primitive and it was giving runtime error when tests were run. Under heavy load it was breaking.
Then i changed comparator to:-
private static class CoordinateComparator implements Comparator<Coordinate> {
#Override
public int compare(Coordinate o1, Coordinate o2) {
return o1.x.compareTo(o2.x);
}
}
In this case x is Integer. Then it started working fine.
Any ideas or thoughts why this was happening. I was passing this comparator to Collections.sort(array, comp)

public static <T> void sort(List<T> list, Comparator<? super T> c) would throw
IllegalArgumentException if the comparator is found to violate the Comparator contract.
In your code, the first compare method is inconsistent for the case where o1.x is equal to o2.x. It will return either -1 or 1 depending on the order in which the instances are compared. It should return 0 in this case.
You can fix it as follows:
public int compare(Coordinate o1, Coordinate o2) {
return o1.x < o2.x ? -1 : o1.x > o2.x ? 1 : 0;
}
Though your o1.x.compareTo(o2.x) alternative seems cleaner to me.

Related

Java how to realize function template like C++

My English is not good. So I try to explain my question in code. Please try to answer me in code. It makes me understand easily.
I have a question: In C++,we can realize that like these codes.
int max(int x,int y)
{
return (x>y)?x:y;
}
float max(float x,float y)
{
return (x>y)?x:y;
}
I can do this to expand code
template <class T>
T max(T x, T y)
{
return (x>y)?x:y;
}
How can I realize the similar function in Java.
You can use generics. Because generics do not work with primitives, and objects cannot be compared with greater-than and less-than operators, we must instead restrict the input types to Comparables (things which can be compared) so that we can use the compareTo method instead:
public static <T extends Comparable<T>> T max(T first, T second)
{
return first.compareTo(second) >= 0 ? first : second;
}
Sample usage:
max(1, 2)
will autobox the primitives to Integers (which do implement Comparable<Integer>) and return 2.
The underlying assumption in the c++ code is that the T type supports the > operator. Java doesn't have operator overloading, but the equivalent would be to limit the code to Ts that implement the Comparable interface:
public static <T extends Comparable<T>> T max(T x, T y)
{
if (x.compareTo(y) > 0) {
return x;
}
return y;
}
Or, alternatively, allow the caller to pass a custom Comparator:
public static <T> T max(T x, T y, Comparator<T> cmp)
{
if (cmp.compare(x, y) > 0) {
return x;
}
return y;
}
Use generics. They are like templates but work in runtime
package test;
class BoxPrinter<T> {
private T val;
public BoxPrinter(T arg) {
val = arg;
}
public String toString() {
return "{" + val + "}";
}
public T getValue() {
return val;
}
}
https://www.geeksforgeeks.org/generics-in-java/
More examples here

Sum of ArrayList for different types

Is it possible to write a single method total to do a sum of all elements of an ArrayList, where it is of type <Integer> or <Long>?
I cannot just write
public long total(ArrayList<Integer> list)
and
public long total(ArrayList<Long> list)
together as there will be an error of erasure, and Integer does not automatically extends to Long and vice versa... but the code inside is identical!
Yes, you can implement such a method, since both Integer and Long extend Number. For example you can use a wildcard type for the list element type:
public static long total(List<? extends Number> list) {
long sum = 0;
for (Number n : list) {
if (!(n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof Long)) {
throw new IllegalArgumentException();
}
sum += n.longValue();
}
return sum;
}
This only works for the integral types however, since the sum variable and the return value are of type long.
Ideally you would like to be able to also use the method with Floats and Doubles and return an object of the same type as the list element type, but this is not easy to do for two reasons:
The only thing you can do with a Number is to get its value as one of the primitive number types. You can not sum two of them in a number dependent way.
It is not possible to create a 0-object of the right class.
EDIT: Much later...
Just for fun, lets do this in a nice way for Java. The thing you have to do is to manually provide the two operations mentioned above. A kind of value with two such operation is usually called a monoid in the context of algebra and functional programming.
The problem can be solved by creating objects that represent the monoid operations:
interface MonoidOps<T> {
T id();
T op(T o1, T o2);
}
The total method can now be implemented to take an object of this type in addition to the list:
public static <T> T total(List<T> list, MonoidOps<T> ops) {
T sum = ops.id();
for (T e : list) {
sum = ops.op(e, sum);
}
return sum;
}
To provide MonoidOps implementations for the numeric classes, lets create a simple helper class:
class SimpleMonoidOps<T> implements MonoidOps<T> {
private final T idElem;
private final BinaryOperator<T> operation;
public SimpleMonoidOps(T idElem, BinaryOperator<T> operation) {
this.idElem = idElem;
this.operation = operation;
}
public T id() {
return idElem;
}
public T op(T o1, T o2) {
return operation.apply(o1, o2);
}
}
The MonoidOps implementations can now be written neatly like this:
static final MonoidOps<Integer> INT_MONOID_OPS = new SimpleMonoidOps<>(0, Integer::sum);
static final MonoidOps<Double> DOUBLE_MONOID_OPS = new SimpleMonoidOps<>(0.0, Double::sum);
And the total method would be called like this:
int sum = total(Arrays.asList(1, 2, 3), INT_MONOID_OPS);
You can also use streams in Java 8
public static <T extends Number> long sumList(List<T> list)
{
return list.stream().mapToLong(a -> a.longValue()).sum();
}
You can use Java´s generics for this
public <T extends Number> T total(List<T> list) {
T sum = 0;
for (T n : list) {
sum += n.longValue();
}
return sum;
}
Knowing that T will always be a Number, things are simplified. However, this solution could work also for Strings, if necessary. The only change would be in the extends part.

Getting Compile time error while sorting arrays using generics in java

Here's my code:
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
public class SortingUsingGenerics {
public static void main(String[] args) {
Integer[] intArray = {1,5,4,2,10};
String[] stringArray = {"Ä","X","C","B","M"};
Float[] floatArray = {1.5f,2.8f,0.5f,10.3f,9.5f};
// Sort and Print
printArray(sortArray(intArray));
printArray(sortArray(stringArray));
printArray(sortArray(floatArray));
}
private static <MyArray> void printArray(MyArray[] inputArray) {
for (MyArray element : inputArray) {
System.out.print(element);
}
System.out.println();
}
public static <E> E[] sortArray(E[] inputArray){
if (inputArray instanceof Integer[]){
Collections.sort(Arrays.asList(inputArray),new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
if (o1 == o2) {
return 0;
} else if (o1 > 02) {
return 1;
} else {
return -1;
}
}
});
}
return inputArray;
}
}
The error I am getting is:
The method sort(List<T>, Comparator<? super T>) in the type Collections is not applicable for the arguments (List<E>, new Comparator<Integer>(){})
Could you please explain what I'm doing wrong here?
Your instanceof check doesn't really tell the compiler that inputArray is an Integer[] - the compile-time type is still just E[].
However, you can cast perfectly easily, at which point it will work:
if (inputArray instanceof Integer[]) {
Integer[] integers = (Integer[]) inputArray;
Collections.sort(Arrays.asList(integers), ...);
}
Or even just:
if (inputArray instanceof Integer[]) {
Collections.sort(Arrays.asList((Integer[]) inputArray), ...);
}
However, when you have a generic method and then do specific things for specific types, you should at least consider whether you really want a generic method after all.
In this scenario, there's not much value in deciding what to do based on if the array is an Integer[], a Float[], or a String[] - all of them implement the Comparable interface. Since the method doesn't allow for it, it doesn't make sense to sort anything that isn't Comparable either - we don't allow for the passing of a custom Comparator which would address this issue.
In that scenario, what would be most ideal is if you relied on the natural behavior of Comparable instead of your hand-written comparison method.
public static <E extends Comparable<E>> E[] sortArray(E[] inputArray){
Collections.sort(Arrays.asList(inputArray), new Comparator<E>() {
#Override
public int compare(E o1, E o2) {
return o1.compareTo(o2);
}
});
return inputArray;
}
This approach ensures that whatever E you pass in that it's also a Comparable, so you can simply delegate to each object's compareTo method, while preserving the required type bound on the anonymous Comparator.

Sorting Array in Java by Arrays.sort;

I implemented my own class myclass. I wrote following code for sorting
Arrays.sort(arrayForSortingInterval, new Comparator<myclass>() {
public int compare(myclass o1, myclass o2) {
return o1.minute <= o2.minute ? 1 : 0;
}
});
My array is declared as myclass[] arrayForSortingInterval = new myclass[lengthIntervalArray*2]; and myclass has two integer values minute and tag.
But this sorting code doesn't seem to work.
The compare method needs to return a negative number when the left object is less than the right one, zero when the two are equal, and a positive number when the left object is greater than the one on the right. One way of achieving this is calling Integer.compare (assuming that minute is an int in your myclass class):
public int compare(myclass o1, myclass o2) {
return Integer.compare(o1.minute, o2.minute);
}
Your comparator is wrong. It should: Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
You comparator method is incorrect, since it is not antisymmetric (compare a to b returns 1, then b to a returns 0).
you should simply return o1.minute - o2.minute
Your compare function is incorrect -1, 0 or 1 for less then, equals or greater respectively.
public int compare(myclass o1, myclass o2) {
// return o1.minute <= o2.minute ? 1 : 0;
if (o1.minute < o2.minute) {
return -1;
} else if (o1.minute > o2.minute) {
return 1;
}
return Integer.compare(o1.tag, o2.tag);
}

What is the best way to get min and max value from a list of Comparables that main contain null values?

I am thinking about something like this:
public static <T extends Comparable<T>> T minOf(T...ts){
SortedSet<T> set = new TreeSet<T>(Arrays.asList(ts));
return set.first();
}
public static <T extends Comparable<T>> T maxOf(T...ts){
SortedSet<T> set = new TreeSet<T>(Arrays.asList(ts));
return set.last();
}
But is not null safe, which is something I want too.
Do you know a better way to solve this problem?
EDIT:
After the comments I have also tried min():
public static <T extends Comparable<T>> T minOf(T...ts){
return Collections.min(Arrays.asList(ts), new Comparator<T>(){
public int compare(T o1, T o2) {
if(o1!=null && o2!=null){
return o1.compareTo(o2);
}else if(o1!=null){
return 1;
}else{
return -1;
}
}});
}
What do you think of that?
What's wrong with Collections.max?
And why do you care about null safety? Are you sure you want to allow nulls to be in your Collection?
If you really need to exclude "null" from the result, and you can't prevent it from being in your array, then maybe you should just iterate through the array with a simple loop and keep track of the "min" and "max" in separate variables. You can still use the "compare()" method on each object to compare it with your current "min" and "max" values. This way, you can add your own code for checking for nulls and ignoring them.
EDIT: here's some code to illustrate what I'm talking about. Unfortunately there is an edge case you need to consider - what if all of the arguments passed in are null? What does your method return?
public static <T extends Comparable<T>> T minOf(T...ts){
T min = null;
for (T t : ts) {
if (t != null && (min == null || t.compareTo(min) < 0)) {
min = t;
}
}
return min;
}
public static <T extends Comparable<T>> T maxOf(T...ts){
T max = null;
for (T t : ts) {
if (t != null && (max == null || t.compareTo(max) > 0)) {
max = t;
}
}
return max;
}
You should not implement Comparable to accept null, as it breaks the interface's contract.
From https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html :
Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.
You must instead create a new interface, e.g. ComparableNull instead.
See also:
What should int compareTo() return when the parameter string is null?
How to simplify a null-safe compareTo() implementation?

Categories