• Post Reply Bookmark Topic Watch Topic
  • New Topic

Mastering Lambdas: What factors considered in designing functional interfaces in java.util.function?  RSS feed

 
S G Ganesh
Author
Ranch Hand
Posts: 93
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Maurice,

The java.util.function package provides numerous functional interfaces. I find it hard to understand the design of this package (perhaps because I am relatively new to lambdas in Java).

1. There are functional interface variants only for three corresponding primitive types (int, long and double). It confuses users, for example, those who want to use char type. And there are hard questions to answer: If and when generics support is added for primitive types, what would happen to these variants? There are inconsistencies as well, for example, why is only BooleanSupplier provided but not Boolean variants for other functional interfaces?

2. How/why only Consumer, Function, Predicate and Supplier (plus the operator variants) are supported?

Consider the following functional interface:



To my knowledge there is no equivalent functional interface is provided in the java.util.function package for this which is a commonly required functionality (please correct me if I am wrong). However, a slight variation in this interface and I pass a type T, I can use the Consumer interface instead of defining my own functional interface like this. Are such aspects conscious design decisions or omissions (by mistake)?

Thanks!

Best regards,
Ganesh




 
Campbell Ritchie
Sheriff
Posts: 53779
128
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I suspect the reason for having Streams etc supporting ints, longs and doubles is that those are the types one usually uses for arithmetic. You don't usually do arithmetic on the other primitives.

Yes, I know you can do arithmetic on chars for coding, a=1, b=2, z=26, and some people insist on doing float arithmetic, but those are unusual situations.
 
Rob Spoor
Sheriff
Posts: 20903
81
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You hardly ever need special support for chars, because in most cases the int specific interfaces work just fine. For instance, Character::isWhitespace is an IntPredicate, because Character.isWhitespace is overloaded to take an int. (In fact, isWhitespace(char) delegates to isWhitespace(int)).

As for your interface example, no new functional interface was added because one already existed: java.lang.Runnable. Just like your example, Runnable.run takes no arguments and returns nothing.
 
Maurice Naftalin
Author
Greenhorn
Posts: 20
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Ganesh

The primitive stream types (int, long, double) were chosen both because you can define specialised arithmetic operations on them, as Campbell says, and because map operations on them – which could be done with the wrapper classes – are way more efficient with primitives. char is a corner case – awkward, but not worth polluting the API for.

It may be that generic specialisation on primitives will eventually make this part of the API redundant, but it would have been a huge gamble to have counted on that during the design of Java 8.

Rob is correct about Runnable – it fits your requirement. In general, though, I don't think it's hugely important that java.util.function should be complete when it's so easy to define any variant interface that you need. There's always a need to balance the convenience of having a wide variety of convenience methods or interfaces on an API with the problem of learnability, which gets worse as the API gets larger. In the book I call java.util.function a "starter kit".

I don't know why BooleanSupplier is there. I suspect they just ran out of time to clean everything up from previous design iterations

Regards
Maurice
 
Campbell Ritchie
Sheriff
Posts: 53779
128
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Maurice Naftalin wrote:. . . I suspect they just ran out of time . . .


Or simply forgot. I have seen a blog by Cai Horstmann complaining that the good ol' Scanner class wasn't given a lines() method to return a Stream. Maybe they forgot that too.
 
Rob Spoor
Sheriff
Posts: 20903
81
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think they added BooleanSupplier because they also had a ToBooleanFunction. It's just called Predicate instead.

However, I don't see much need for boolean support because auto boxing and unboxing of booleans is so cheap. Unlike numeric types, a boolean can have only two values - true or false. Both have a matching object in java.lang.Boolean. That means that auto boxing any boolean will always yield one of those two objects (unlike int or long boxing which only cache 256 values by default, or double boxing which caches nothing at all). In other words, for boolean you can just use Boolean instead.
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!