Java - Inline definition of comparator for Collection.max - java

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();
}

Related

Calling a function without doing a new

I wrote a sort function and class in Java:
public class MiscellaneousUtilities {
/**
* Changes a list of "First Last" to "Last, First" and "First Middle Last" to "Last, First Middle", etc.
*/
public static Function<String, String> ToLastFirstFunction = new Function<String, String>() {
#Override
public String apply(String nm) {
String[] nmarr = nm.split(" ");
int last = nmarr.length - 1;
String res = nmarr[last];
if (last > 0) {
res += ",";
}
for (int i = 0; i < last; i++) {
res += " " + nmarr[i];
}
return res;
};
};
}
When I want to use it I can't just say MiscellaneousFunctions.ToFirstLastFunction()
I have to do a new MiscellaneousFunctions().ToFirstLastFunction;
I tried putting static in front of the class declaration but it allows only public, final and abstract. Looking at the Math class if I want to use Math.min() I don't have to do a new Math().min(). Math is also defined as a class that does not have static in front of it, and min() does as does ToFirstLastFunction, so I don't understand the difference.
That's because you have to call that function with an apply like this:
MiscellaneousFunctions.ToFirstLastFunction.apply("yourstring");
You can add an other static function as a shorthand though:
public static String toFirstLast(String str) {
return ToLastFirstFunction.apply(str);
}
The main difference between Math.min and your solution that Math.min is a regular static method while you have a Function object and those can be called with apply.
Math.min() is a a method not a function, declared like this in Math.class:
public int min(int a, int b) {
...
}
... and it is methods like this that you can invoke directly as in int x = Math.min(3,2).
You have created a public static class variable called ToLastFirstFunction -- that's not something you can call like a method. But you can do things with it using the methods in the java.util.function.Function interface -- the simplest being apply():
String out = MiscellaneousFunctions.toFirstLastFunction.apply("John Doe");
(I changed the capitalisation of your identifier -- find out about Java capitalisation conventions)
It is not the case that you can call your public static Function<...> using new MiscellaneousFunctions().toFirstLastFunction("John Doe") -- I'm not sure why you thought it was so.
You can do new MiscellanousFunctions().toFirstLastFunction.apply("John Doe") -- but your compiler should warn you about accessing a static variable via an instance. MiscellanousFunctions.toFirstLastFunction.apply() is the right way.
So the short answer to your question is: if you want to invoke it that way, write it as a method.
But if that's the case, why would you define an operation as a function, rather than a method?
Well, functions have the benefit that, unlike methods(*), they are objects -- so you can pass them around, put them in collections, assign them to variables. And they have methods like compose() and andThen() which return a new function that combines this function with another.
So you can do things like:
Map<String,Function<String,String> nameTranslationStrategies = new HashMap<>();
nameTranslationStrategies.put(
"no change", x -> x);
nameTranslationStrategies.put(
"to first-last",
MiscellaneousFunctions.toFirstLastFunction);
nameTranslationStrategies.put(
"capitalised first-last",
MiscellaneousFunctions.toFirstLastFunction
.andThen( s -> s.toUpperCase());
...
String nameTranslationOption = config.getProperty("nameTranslationOption");
String name = nameTranslationStrategies
.get(nameTranslationOption)
.apply(inputString);
Java programmers managed for decades without this feature -- functions didn't exist until Java 8. But you can do lots of neat things with them.
Even so, this isn't a reason to write your code as a Function bound to a static variable, since you can access ordinary methods as functions using the :: syntax:
Function<Double,Double> logarithm = Math::log;
double x = logarithm.apply(2.0);
Note also, that you've used a long-winded syntax to define your function:
public static Function<String, String> slimify = new Function<String, String>() {
#Override
public String apply(String s) {
return "slim says " + s;
}
}
... can be written as:
public static Function<String,String> slimify = s -> {
return "slim says " + s;
}
... or even (since this one's a one-liner)
public static Function<String,String> slimify = s -> "slim says " + s;
It's good to know the long-winded way, because it shows how functions work behind the scenes. But in real world code, the shorter form is the way to go, as it is more expressive: the intent of the code isn't hidden by clutter. This is such a quick and easy way of expressing a function, that people often use them in-line rather than assign them to a variable -- as I have done in the map example above.
(*) I said that methods are not objects. This isn't strictly true -- partly because you can get one as an object using ::, but also because you can use Java's Reflection API to access classes and methods as objects. But you don't want to use Reflection, unless you really know you need to.
Math.min() is a public static method called min, your Function is a Function object, it's not a method. Your object has a method apply and you have to use that method for what you want to achieve, like this:
MiscellaneousFunctions.ToFirstLastFunction.apply(something)

Can I have function types in Java's Enum like Swift?

Is it possible to write an equivalent code in Java for the following swift code? In fact, I want to know if it's possible to have a case of functions inside Java's enum (X, Y in MyEnum)
enum MyEnum{
case X((Int) -> String)
case Y((Double) -> Int)
}
No, you can't; at least, not if you want the differing types to be available when you use the enum. All enum values have to have the same type.
When you want "enum" values to have heterogenous types, you could use a class with static final fields:
final class MyHeterogeneousEnum {
private MyHeterogeneousEnum() {} // Not instantiable.
static final Function<Integer, String> X = ...;
static final Function<Double, Integer> Y = ...;
}
which allows you to use the values with their full type information:
String s = MyHeterogeneousEnum.X.apply(123);
Integer i = MyHeterogeneousEnum.Y.apply(999.0);
Of course, you don't have useful methods like name(), or values() to iterate over the constants in this class, nor is it inherently serializable. You can make implement these yourself - but for values() you have to use wildcards in the return type, in order that all values can be returned:
static Iterable<Function<?, ?>> values() {
return Collections.unmodifiableList(Arrays.asList(X, Y));
}
However, note that a Function with a wildcard input type parameter is pretty much useless: you can't actually pass anything into it (other than null); so the values() method has limited utility.
It is possible (technically), but it might not be that useful, as creating a simple class, that consumes a Function instance.
As you might already know, in Java, the enums represent one or more constants of the same type, which could have their own properties - this include java.util.Function instances. However, these Function instances cannot be passed dynamically at Runtime, but should be rather set at compile time, so that the constant is created.
Of course, you could make each enum constant have a different typed Function, by just creating the enum's constructor Generic:
enum MyEnum {
X((String x) -> "Hello"), Y((Double d) -> 1);
Function<?, ?> function;
MyEnum(Function<?, ?> function) {
this.function = function;
}
}
This, however, is not quite useful (although it compiles just fine). The Function in X doesn't use it's String parameter and returns a fixed value. So does the one in Y.
I'd rather introduce two separate instances of the same class:
class Instance<T, U> {
private Function<T, U> function;
public Instance(Function<T, U> function) {
this.function = function;
}
}
This will allow you to dynamically pass a Function instance, instead of setting it at compile-time.
Yes for sure you can, in java enums can be more that just constants... every one of it values can be an anonymous class (take a look to TimeUnit.class for example)
now, you can do somthing like:
interface IFunction {
double getY(double x);
}
enum Function implements IFunction {
LINE {
#Override
public double getY(double x) {
return x;
}
},
SINE {
#Override
public double getY(double x) {
return Math.sin(x);
}
}
}
and then the implementation
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Function.LINE.getY(i));
System.out.println(Function.SINE.getY(i));
}
}

Anonymous Inner Class - Collections sort

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).

Maximum of Stream with custom Comparator

Below is my code written specifically to use custom Comparator with max in Java 8 Stream.
import java.math.BigDecimal;
import java.util.*;
public class BigDecimalMax {
public static BigDecimal getBigDecimalMax(List<forTest> list) {
return list.stream()
.filter(t -> t.id % 2 == 0)
.max(forTestComparator::compare) //<-- syntax error ----------
.orElse(null);
}
public static class forTestComparator implements Comparator<forTest> {
#Override
public int compare(forTest val1, forTest val2) {
return val1.value.compareTo(val2.value);
}
}
public static void main(String[] args) {
List<forTest> lst = new ArrayList<>();
Random rn = new Random();
BigDecimalMax bdm = new BigDecimalMax();
for (int i=1; i<22; ++i) {
lst.add(bdm.new forTest(i, BigDecimal.valueOf(rn.nextLong())));
}
System.out.println(getBigDecimalMax(lst));
}
class forTest {
public int id;
public BigDecimal value;
forTest(int id, BigDecimal value) {
this.id = id;
this.value = value;
}
#Override
public String toString() {
return "forTest{" +
"id=" + id +
", value=" + value +
'}';
}
}
}
I'm getting a syntax error on a method reference which I don't understand.
Error:(15, 18) java: incompatible types: invalid method reference
cannot find symbol
symbol: method compare(BigDecimalMax.forTest, BigDecimalMax.forTest)
location: class BigDecimalMax.forTestComparator
while IntelliJ IDEA complains that Non-static method cannot be referenced from a static context.
What exactly am I doing wrong here?
ADDITIONAL EXPLANATION (04/24/14):
I understand now the reason for the syntax error. Thank you.
Was custom Comparator actually needed here?
Since BigDecimal implements Comparable but does not seem to implement Comparator ( it has CompareTo() but no Compare()) I thought that custom Comparator was necessary. That's why I could not just use Comparator.comparing(ft -> ft.value). Is there a flaw in my logic?
Sotirios Delimanolis' answer shows how to fix the problems, but I have a few things to add.
If you already have a class that implements Comparator, you don't need to use a method reference to its compare() method. You can just pass an instance of it directly, since max() takes a reference to a Comparator:
.max(new forTestComparator())
or
forTestComparator instance = new forTestComparator();
...
.max(instance)
However, the combinator functions on Comparator usually make it unnecessary to have a class that implements Comparator. For example, you can get rid of the forTestComparator class entirely and just do this:
.max(Comparator.comparing(ft -> ft.value))
or if forTest were to have the obvious getValue() method, one could rewrite the stream max() call as follows:
.max(Comparator.comparing(forTest::getValue))
In addition, if you wanted to make forTest implement the Comparable interface, you could do this:
public class forTest implements Comparable<forTest> {
#Override
public int compareTo(forTest other) {
return this.value.compareTo(other.value);
}
...
}
and the way to use max() on a Comparable is:
.max(Comparator.naturalOrder())
Two style notes:
I strongly discourage using orElse(null) on instances of Optional. This is allowed, though probably its main purpose to retrofit use of new Java 8 APIs into code that's expecting null to indicate the absence of a value. Avoid orElse(null) if you possibly can, since this forces the caller to check for null. Instead, substitute an actual value to replace an absent value, or return the Optional itself to the caller, so the caller can apply whatever policy it wants.
I recommend sticking to the established Java naming conventions of capitalized, mixed-case class names. The class names forTest and forTestComparator make this code kind of difficult to work with, since they don't look like class names.
forTestComparator#compare is an instance method. You need an instance method reference, as opposed to a static method reference that you have.
Something like
new forTestComparator()::compare
or the long way (your class doesn't have instance state, so you don't really care about the reference)
forTestComparator instance = new forTestComparator(); // fix for Java conventions
return list.stream()
.filter(t -> t.id % 2 == 0)
.max(instance::compare) //<-- syntax error ----------
.orElse(null);
See the Java tutorial on method references here.
Reference to an instance method of a particular object -> ContainingObject::instanceMethodName
Side note, this
return list.stream()
.filter(t -> t.id % 2 == 0)
.max(new forTestComparator()::compare)
.orElse(null);
resolves in a forTest value. You need to change the return type of your method.

How to avoid unsafe cast warnings with Java Generics

I'm quite new to Java Generics. But I've read a lot of summary links and examples. But I cannot get the simplest method right. I hope somenoe can help:
I want to create a HashMap which maps one undefined Object to another one. Both objects may one of String or Integer.
So I wrote this:
private final HashMap<L, R> left2Right = new HashMap<L, R>();
Extractor<?> extLeft = Extractor.getInstance(0);
Extractor<?> extRight = Extractor.getInstance(1);
L leftVal = extLeft.extract(d, i);
R rightVal = extRight.extract(d, i);
this.left2Right.put(leftVal, rightVal);
So far so good... But I have problems implementing the extractor-objects. They are instanciated by a factory pattern. I did it like this (simplyfied):
abstract class Extractor<E> {
abstract E extract(DTable source, int row);
static <E> Extractor<E> getInstance(int type) {
if(type == 0)
return new IntExtractor();
else
return new StringExtractor();
}
}
class IntExtractor extends Extractor<Integer> {
#Override
Integer extract(DTable source, int row) {
int value = 5;
return new Integer(value);
}
}
class StringExtractor extends Extractor<String> {
#Override
String extract(DTable source, int row) {
String retVal = "hello";
return retVal;
}
}
It compiles, but I get Unsave cast warnings on casting the Integer/String to E. What am I doing wrong? I know, I can simply supress the warnings. But I thought exactly this should be the advantage of Java generics? I cannot make this cast save, because I dont know, which type 'E' really "is"...
Or am I doing something basically wrong?
Note:
I edited my code to a "new" question after I used some information from the first answer...
Your extractors aren't really generic at all. It sounds like you want something like:
public interface Extractor<P> {
P extract(DTable source, int row);
}
but then make the implementations non-generic:
class IntExtractor implements Extractor<Integer> {
Integer extract(DTable source, int row) {
int value = 5;
return new Integer(value);
}
}
Fundamentally your current code is broken, in that I could write:
IntExtractor<String> extractor = new IntExtractor<String>();
String x = extractor.extract(...);
... that would obviously fail, but only at execution time.
I'd say you're doing something basically wrong. If it is an IntExtractor and a StringExtractor, you don't need generics. Just define methods
Integer extract(DTable source, int row)
and
String extract(DTable source, int row)
The Problem isn't your code per-se. The task itself cannot be solved without unsafe casts. Read your own sentence again:
I want to create a HashMap which maps one undefined Object to
another one. Both objects may one of String or Integer.
Java Generics cannot solve this problem for you, because you have to know the type beforehand, otherwise you have to cast.
To be honest, I do not know what you want to achieve with the code you posted, but If you want to use a HashMap, you can do it like this:
private final HashMap<String, Integer> left2Right = new HashMap<String, Integer>();
left2Right.put("one", 1);
int numberOne = left2Right.get("one");
In this case you do not have to cast the values, because the HashMap has String keys and Integer values. If you want to put different types as values, you have to use a supertype of all values. This super type might be Object, the root of the hierarchy. But in those cases you have to cast - because you do not know what kind of object the value is.
private final HashMap<String, Integer> left2Right = new HashMap<String, Object>();
left2Right.put("one", 1);
left2Right.put("two", new Date());
// Because the compiler cannot know that type "one" might be, this isn't allowed and you have to cast the value. It might be anything - in this example Date or Integer.
int numberOne = left2Right.get("one");
I hope that helps.
Both P and E seem not to be used for the input of the extractors so why are you even having them? Just return int and String and be done with it.

Categories