Identity for BinaryOperator

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






An identity, by definition, returns its input without any modification. If the input is two values, its output must also be two values. What you want is not an identity, but some sort of distinct or group operation before processing the values. (I don't speak modern Java, but in C# that would literally be .Distinct and .GroupBy.)

– Jeroen Mostert
Sep 12 '18 at 13:17



.Distinct


.GroupBy






The problem is not in your code, but in the Sonar alert instead. Just turn it off.

– Federico Peralta Schaffner
Sep 12 '18 at 13:44






Some functional languages only have unary functions. In these languages, a function accepting a tuple is equivalent to a binary function in Java. Identity for such a function is easy when you think of it in this way: if a tuple is input, it must also be the output.

– user633183
Sep 12 '18 at 13:45





3 Answers
3



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.


BinaryOperator.identity


t



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.


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.






Well, I agree to what you've stated here, except for the last part: 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. In fact it is quite useful, as OP is showing here. Another use case is when implementing collectors and you need to provide a combiner function that you know will never be used (because i.e. the stream is sequential). Besides, BinaryOperator does provide maxBy(Comparator) static method (and also minBy), so it's valid to wonder why there's no i.e. first or second methods...

– Federico Peralta Schaffner
Sep 12 '18 at 15:41



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


BinaryOperator


maxBy(Comparator)


minBy


first


second






@FedericoPeraltaSchaffner "common" is kind of subjective. I've never needed that, and I work with the JDK on a daily basis. By contrast, I've needed Function.identity probably 100s of times. The JDK is supposed to be a collection of broadly useful tools. It's not designed to contain absolutely everything a developer might ever need. If you add a getFirst, people will wonder where getSecond is. If you add both of those for BinaryOperator, why not add similar ones for the other 42 functional interfaces? Boom - you've now got ~100 basically useless methods cluttering the API.

– Michael
Sep 12 '18 at 15:53



Function.identity


getFirst


getSecond


BinaryOperator






I absolutely agree with you, I was playing the role of the devil's advocate a little bit... The problem with the question is not that there doesn't exist a method to choose the first or second element, but that Sonar is throwing an alert, when it shouldn't...

– Federico Peralta Schaffner
Sep 12 '18 at 15:56



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


T



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.


BinaryOperator


identity


foldLeft


foldRight


foldLeftIdentity/foldRightIdentity






what's your thought on the implementation of any for returning any value as in the merger?

– nullpointer
Sep 12 '18 at 13:45


any






@nullpointer :) that is all I can say. probably Math.random is too expensive here, I would go for something cheaper like long nt = System.nanoTime(); ((nt >>> 32) ^ nt) > 0 ? ... : ... but I've seen this somewhere else already :) (of course the cheapest and fastest random would have to be taken here)

– Eugene
Sep 12 '18 at 14:05


Math.random


long nt = System.nanoTime(); ((nt >>> 32) ^ nt) > 0 ? ... : ...



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 :


any


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






that btw is a very interesting merger :)

– Eugene
Sep 12 '18 at 13:19






I guess you are right, it just looks weird to me.

– Eugene
Sep 12 '18 at 13:24






You know that your random implementation won't pick a random argument each time, but will choose one implementation when called, and then will return the same argument all times. btw I didn't downvote

– Federico Peralta Schaffner
Sep 12 '18 at 13:48







I remember I asked something about that here and Stuart Marks kindly answered... :D

– Federico Peralta Schaffner
Sep 12 '18 at 14:15






I’d use ThreadLocalRandom.current().nextBoolean() instead of Math.random() < 0.5. An alternative would be (a,b) -> assert Objects.equals(a, b); return a;

– Holger
Sep 12 '18 at 17:30


ThreadLocalRandom.current().nextBoolean()


Math.random() < 0.5


(a,b) -> assert Objects.equals(a, b); return a;



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)