Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identity for BinaryOperator

I see in Java8 in UnaryOperator Interface following piece of code which does nothing on parameter and returns same value.

static <T> UnaryOperator<T> identity() {
    return t -> t;
}

Is there anything for BinaryOperator which accepts two parameters of samekind and returns one value

static <T> BinaryOperator<T> identity() {
    return (t,t) -> t;
}

why I am asking this question is for below requirement,

List<String> list = Arrays.asList("Abcd","Abcd");
Map<String,Integer> map = list.stream().collect(Collectors.toMap(str->str, 
str->(Integer)str.length(),(t1,t2)->t1));
System.out.println(map.size());

in above code I don't want to do anything for two values of same key, I just wanted return one value, because in my case for sure values will be same. As am not using t2 value Sonar throwing error, So I am finding out is there any thing like UnaryOperator.identity() for BinaryOpertor also in java8

like image 975
Karunakar Reddy L Avatar asked Sep 12 '18 13:09

Karunakar Reddy L


3 Answers

Your question doesn't really make sense. If you were to paste your proposed BinaryOperator.identity method into an IDE, you would immediately see that it would complain that the identifier t is declared twice.

To fix this, we need a different identifier for each parameter:

return (t, u) -> t;

Now we can clearly see that this is not an identity function. It's a method which takes two arguments and returns the first one. Therefore the best name for this would be something like getFirst.

To answer your question about whether there's anything like this in the JDK: no. Using an identity function is a common use case, so defining a method for that is useful. Arbitrarily returning the first argument of two is not a common use case, and it's not useful to have a method to do that.

like image 122
Michael Avatar answered Oct 30 '22 22:10

Michael


T means they have the same types, not the same values, that is not an identity per-se.

It just means that BinaryOperator will be used for the same types, but providing an identity for different values... this somehow sounds like foldLeft or foldRight or foldLeftIdentity/foldRightIdentity, which java does not have.

like image 45
Eugene Avatar answered Oct 30 '22 23:10

Eugene


Your code seemingly can be improved as

List<String> list = Arrays.asList("Abcd", "Abcd");
Map<String, Integer> map = list.stream()
            .collect(Collectors.toMap(Function.identity(), String::length, (a, b) -> a));
System.out.println(map.size());

Or possibly for your use case I don't want to do anything for two values of same key, I just wanted return one value, you may just choose to randomly return any value in using an implementation as following:

private static <T> BinaryOperator<T> any() {
    return Math.random() < 0.5 ? ((x, y) -> x) : ((x, y) -> y);
}

and then in your code use it as

Map<String, Integer> map = list.stream()
            .collect(Collectors.toMap(Function.identity(), String::length, any()));

Thanks to the suggestions from Holger, Eugene, and Federico, there are other efficient implementations of the any method that can actually involve using :

private static <T> BinaryOperator<T> any() {
    // suggested by Holger
    return ThreadLocalRandom.current().nextBoolean() ? ((x, y) -> x) : ((x, y) -> y);
    // suggested by Eugene
    long nt = System.nanoTime(); 
    ((nt >>> 32) ^ nt) > 0 ? ((x, y) -> x) : ((x, y) -> y);
}
like image 28
Naman Avatar answered Oct 30 '22 22:10

Naman