I am creating a Comparator as Anonymous inner class and I am not sure if its the best approach. I am creating it only once in my code, but what I am not sure is whether that inner class is created each time I am sorting a list. For example in an application if I am calling the sort method using that comparator 10 times, would there be ten extra classes created?
Collections.sort(originalList, new Comparator<User>() {
#Override
public int compare(User o1, User o2) {
int value1 = o1.getPropertyCode().compareTo(o2.getPropertyCode());
if (value1 == 0) {
int value2=o1.getPropertyValue().compareTo(o2.getPropertyValue());
return value2;
}
return value1;
}
});
vs
Collections.sort(originalList, new SomeComparator());
Anonymous classes are turned into a regular class definition by the compiler and are actually given a name like OutterClass$1, you can not refer to that class by that name but you can do for example new Object() {}.class.getName() to see that it's always the same. Whenever your code hits the line in question it's using just 1 class - whether you give it an explicit name or not. Your 2 options are basically the same.
But when you read your line of code up until Collections.sort(originalList, new you should be aware that that new creates a new instance (not a class) every time. I.e. it allocates memory, initializes the thing, .. none of which is needed more than once because the created comparator object will never differ.
What you'll want to do is either storing the created comparator once in a field like so (or like in Java's own source String.CASE_INSENSITIVE_ORDER)
private static final Comparator<User> USER_COMPARATOR = new Comparator<User>() {
#Override
public int compare(User o1, User o2) {
int value1 = o1.getPropertyCode().compareTo(o2.getPropertyCode());
if (value1 == 0) {
int value2=o1.getPropertyValue().compareTo(o2.getPropertyValue());
return value2;
}
return value1;
}
};
private void someCode() {
Collections.sort(originalList, USER_COMPARATOR);
}
Or with Java 8 you can turn it into a lambda (notice the missing new) which also doesn't create new instances every time
Collections.sort(originalList, (o1, o2) -> {
int value1 = o1.getPropertyCode().compareTo(o2.getPropertyCode());
if (value1 == 0) {
int value2=o1.getPropertyValue().compareTo(o2.getPropertyValue());
return value2;
}
return value1;
});
It depends. If you have that Comparator in a method, then at each call a new one will be instantiated. Moreover, that Comparator will contain a reference to the encompassing class.
On the other hand, if you define that anonymous inner class as a static field, then there will be only one (per class loader).
Related
I have a requirement where in the function takes different parameters and returns unique objects. All these functions perform the same operation.
ie.
public returnObject1 myfunction( paramObject1 a, int a) {
returnObject1 = new returnObject1();
returnObject1.a = paramObject1.a;
return returnObject1;
}
public returnOject2 myfunction( paramObject2 a, int a){
returnObject2 = new returnObject2();
returnObject2.a = paramObject2.a;
return returnObject2;
}
As you can see above, both the function do the same task but they take different parameters as input and return different objects.
I would like to minimize writing different functions that does the same task.
Is it possible to write a generic method for this that can substitute the parameters based on the call to the function?
paramObject and returnObject are basically two classes that have different variables. They are not related to each other.
My objective is that I do not want to do function overloading since the functions do almost the same work. I would like to have a single function that can handle different input and different return output.
my aim is to do something like this (if possible):
public static < E > myfunction( T a, int a ) {
// do work
}
The return type E and the input T can keep varying.
you can using the 3rd apply method to remove the code duplications, you separate creation & initialization from the apply method in this approach. and don't care about which type of T is used. for example:
returnObject1 myfunction(paramObject1 a, int b) {
return apply(returnObject1::new, b, value -> {
//uses paramObject1
//populates returnObject1
//for example:
value.foo = a.bar;
});
}
returnOject2 myfunction(paramObject2 a, int b) {
return apply(returnOject2::new, b, value -> {
//uses paramObject2
//populates returnObject2
//for example:
value.key = a.value;
});
}
<T> T apply(Supplier<T> factory, int b, Consumer<T> initializer) {
T value = factory.get();
initializer.accept(value);
//does work ...
return value;
}
Note the 2 myfunction is optional, you can remove them from you source code, and call the apply method directly, for example:
paramObject2 a = ...;
returnObject2 result = apply(returnOject2::new, 2, value -> {
//for example:
value.key = a.value;
});
Make interface Foo and implement this interface in both paramObject1 and paramObject2 class. Now your method should be look like:
public Foo myFunction(Foo foo, int a){
//Rest of the code.
return foo;
}
I have a class representing a column. It has a comparator which looks something like this:
class Column
{
int xposition;
int usage;
#Override
public int compare(Object arg0, Object arg1)
{
// sort logic
}
}
I have a TreeSet of Columns. I want to sort the TreeSet first by x-position, and then at some point by usage.
What I tried is to create a superclass, such as Column2, that extends Column and has a different compare method. However that makes converting from Column to Column2 (or visa versa) very ugly. I also thought of a flag in the Column that indicates how to do the sort, but that would mean modifying all the objects in order to change the sort criteria.
Is there any better way to do this?
I would have the comparison logic in a set of external Comparators to represent the different sorting cases you have, and then create a new TreeSet when you want to change the sort:
class Column
{
int xposition;
int usage;
public static final Comparator<Column> SortByX = new Comparator<Column>() {
#Override
public int compare(Column c1, Column c2)
{
return Integer.compare(c1.xposition, c2.xposition);
}
};
public static final Comparator<Column> SortByUsage = new Comparator<Column>() {
#Override
public int compare(Column c1, Column c2)
{
return Integer.compare(c1.usage, c2.usage);
}
};
}
TreeSet<Column> cols = new TreeSet<>(Column.SortByX);
Then, to change the sort:
TreeSet<Column> updated = new TreeSet<>(Column.SortByUsage);
updated.addAll(cols);
cols = updated;
With appropriate synchronization if this is happening in a multi-threaded environment.
Whatever you do, do not change the behavior of an object's Comparator using mutable state. If you do, you could easily "lose track" of an object after it has been put into a collection like TreeSet.
Strategy pattern
What you want to achieve seems a classic use case for the Strategy pattern (e.g. Real World Example of the Strategy Pattern)
In essence, you want to package up this comparison function into something that you can put in a separate field for your column class - a plain class with that single function that implements Comparable would work. Then, your column would just delegate the call to whatever comparator is stored in that field.
This is exact use case of Guava's ComparisionChain:
Example taken from here :
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(this.xposition, that.xposition)
.compare(this.usage, that.usage)
.result();
}
Like Sean Bright answer, I'd use external Comparator and if you are working with Java 8, you can do it pretty easily:
public static final Comparator<Foobar> NAME_THEN_AGE =
Comparators.comparing(Foobar::getName, String.CASE_INSENSITIVE_ORDER)
.thenComparing(Foobar::getAge)
;
....
TreeSet<Foobar> foobar = new TreeSet<>(NAME_THEN_AGE);
However, better remaindered that not, it is generally a bad idea to override Comparable on a child class - perhaps it should be final on the parent or one should create a protected compareTo0(A) doing the common work (to avoid comparing object by their parent class).
There are reason for that, and one such is the following (from the Javadoc of Comparable.compareTo):
The implementor must ensure sgn(x.compareTo(y)) ==
-sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an
exception.)
Let's say you have class B and C extending A and A implements Comparable<A>:
class A implements Comparable<A> {
#Override
public int compareTo(A other) {return ...;}
}
class B extends A {
#Override
public int compareTo(A other) {return compareToAsB(((B)other));}
}
class C extends A {
#Override
public int compareTo(A other) {return compareToAsC(((C)other));}
}
It does not really matter what A::compareTo returns. Neither what compareToAsB and compareToAsC does.
The problem is however here:
A a = ...;
B b = ...;
C c = ...;
a.compareTo(b); // ok
a.compareTo(c); // ok
b.compareTo(a); // ko ClassCastException
b.compareTo(c); // ko ClassCastException
c.compareTo(a); // ko ClassCastException
c.compareTo(b); // ko ClassCastException
As quoted in the javadoc, a.compareTo(b) should throw a ClassCastException.
Also, there are part in the Java code (Collections.sort) where it is important to ensure that sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.
I am looking for a Java equivalent for python snippet
max_valued_key = max(str_to_double_map.keys(), key=lambda x: str_to_double_map[x])
I want to something standard like Collections.max
Is there a way to do this with inline definition of Comparator since I don't want to write one more class for every other comparator.
I tried following code unsuccessfully
depScores = foo();
String dep = Collections.max(depScores.keySet(), new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return depScores.get(o1).compareTo(depScores.get(o2));
}
});
depScores variable is not readable from comparator.
Looks like in java inner class cannot access non-final variable from outside!
Thanks in advance!
Just declare depScores as a final variable. If for some reason you can't, create a second (final) variable that points to it.
Local classes can capture variables only if they are final.
As a (very) late addendum, it is trivial to create a custom Comparator from a lambda in Java 8:
String dep = Collections.max(
depScores.keySet(),
Comparator.comparing(k -> depScores.get(k))
);
You can get even more terse by replacing the lambda k -> depScores.get(k) with the method reference depScores::get.
The rules for capturing local variables like depScore are a little more flexible for lambdas than inner classes: captured variables need only be effectively final. In other words, they must be assigned exactly once, though they needn't be explicitly marked final.
What you want is (will be) possible with Java 8:
Map<String,Double> map…
String maxKey=Collections.max(map.keySet(), (x,y)->Double.compare(map.get(x),map.get(y)));
or even shorter
String maxKey = Collections.max(map.keySet(), Comparator.comparingDouble(map::get));
For previous Java version you have to use:
String maxKey=Collections.max(map.keySet(), new Comparator<String>(){
public int compare(String x, String y) {
return Double.compare(map.get(x),map.get(y));
}
});
Problems with map not being final can be circumvented by assigning it to a final variable right before the invocation:
final Map<String,Double> fmap=map;
String maxKey=Collections.max(map.keySet(), new Comparator<String>(){
public int compare(String x, String y) {
return Double.compare(fmap.get(x),fmap.get(y));
}
});
But I think even more straightforward and more efficient will be the following helper method as it does not require any hash lookups:
static <K,V extends Comparable<V>> K keyForHighestValue(Map<K,V> map) {
V maxValue=Collections.max(map.values());
for(Map.Entry<K,V> e:map.entrySet()) {
if(e.getValue()==maxValue) return e.getKey();
}
throw new ConcurrentModificationException();
}
I have a class called Variable
Class Variable{ private String name; private int[] domain; //...etc}
which represents variable in specific structure (constraint satisfaction problem).
I have instantiated set of variables in ArrayList< Variable > and filled up an array of integers.
ArrayList<Variable> vars=new ArrayList<Variable>();
Variable a=new Variable("A",new int[]{1,2});
vars.add(a);
// Define all variables;
int[] cons=new int[vars.size()];
for(int i=0;i<cons.length;i++)
cons[i]=number_of_constraints(vars.get(i));
// cons contains number of involved constraints for each variable
Now I need to sort them descending based on the number of constraints.
In other words: Given list of Objects [(A,{1,2}) , (B,{3,4}) , (C,{5,6}) ] and an array of integers cons={1,2,0} how to sort the list of objects descending based on the array of integers?
Use a sorted collection like a TreeSet
class Variable {
private String name;
private int[] domain;
};
final Set<Variable> variables = new TreeSet<Variable>( new Comparator<Variable>() {
public int compare(Variable o1, Variable o2) {
//Do comparison here
//return -1 if o1 is less than o2
//1 if o1 is greater than o2
//0 if they are the same
}
});
Now you have a sorted Set of your Variables. This is guaranteed to always be sorted.
If you would like to keep Class Variable intact, the following code will sort the given vars outside:
Collections.sort(vars, new Comparator<Variable>() {
public int compare(Variable var1, Variable var2) {
return var2.number_of_constraints() - var1.number_of_constraints();
}});
If you can change Class Variable, let it implement interface Comparable:
class Variable implements Comparable<Variable> {
//...
public int compareTo(Variable other) {
return this.number_of_constraints() -
other.number_of_constraints();
}
}
Then you can sort vars by:
Collections.sort(vars);
As far as a Variable contains numOfConstraints, according to your code, you can make your Variable class implement Comparable interface, like
public class Variuable implements Comparable<Variable> {
private int numOfConstraints;
public int compareTo(Variable other){
if(this == other) { return 0; }
return (numOfConstraints == other.numOfConstraint) ? 0 : ((numOfConstraints > other.numOfConstraint) ? 1 : -1);
}
}
And then use the utility method java.util.Collections.sort(vars);, that's it.
Your Variable class should implement the Comparable interface,
When it does you should implement the compareTo method.
After that you can sort it by calling the Collection.sort method.
If you want to sort by a permutation if your indexes that's just a matter of creating a new ArrayList and mapping each index to the new index (using a for loop)
Here is such a (generic) method
public static <T> ArrayList<T> permutate(ArrayList<T> origin,int[] permutation){
ArrayList<T> result = new ArrayList<T>(permutation.length);
for(int j=0;j<permutation.length;j++){
result.add(null);
}
for(int i=0;i<permutation.length;i++){
result.set(i, origin.get(permutation[i]));
}
return result;
}
You can do myArrayList= permutate(myArrayList, new int{1,2,3});
Here is example usage in a more basic use case (integers):
public static void main(String... args){
ArrayList<Integer> origin = new ArrayList<>(4);
origin.add(1);
origin.add(2);
origin.add(3);
origin.add(4);
int[] per = new int[]{2,1,3,0};
origin = permutate(origin,per);
System.out.println(Arrays.toString(origin.toArray())); //prints [3,2,4,1], your permutation
}
I have created a HashMap object which stores a String as key and corresponding value as int. Now I want to have a Priority Queue which have all the String present in HashMap object with value as reference for assigning priorities. I have written the following code
public class URIQueue {
private HashMap<String,Integer> CopyQURI;
private PriorityQueue<String> QURI;
public class TComparator<String> {
public int compareTo(String s1, String s2) {
if (CopyQURI.get(s2) - CopyQURI.get(s1) >= 0) {
return 1;
} else {
return 0;
}
}
}
public URIQueue() {
CopyQURI=new HashMap<>(100);
TComparator<String> tc=new TComparator<>();
QURI=new PriorityQueue<>(100, tc); //Line x
}
}
Line x is showing error cannot infer type argument for priority queue. Please guide me what mistake I have done.
The error you are referring to states, that it cannot guess the generic type parameter which you have omitted. The reason for that is that the constructor you are using is not known. It is not known, because you second argument is not a comparator. Your comparator has to implement the java.util.Comparator interface in order to be type safe for the constructor to accept.
public class TComparator<String> implements Comparator<String> {
#Override
public int compare(String arg0, String arg1) {
// ...
}
}
Also mind, in the Comparator interface the appropriate method is called compare and not compareTo.
A general advice, I have to agree with Louis Wasserman, for two given arguments a comparator should always return the same result and not depend on the state of the application. It's just too easy not to think of some case and the application is eventually flawed.