Java Reference
In-Depth Information
The main difficulty for Java is backward compatibility, both in the JVM and in existing
programs that use reflection and expect generics to be erased.
Additional syntactic flexibility in generics for function types
Generics proved a wonderful feature when added to Java 5. They're also fine for expressing the
type of many Java 8 lambdas and method references. You can express a one-argument function:
Function<Integer, Integer> square = x -> x * x;
If you have a two-argument function, you use the type BiFunction<T, U, R>, where T is the type
of the first parameter, U the second, and R the result. But there's no TriFunction unless you
declare it yourself!
Similarly, you can't use Function<T, R> for references to methods taking zero arguments and
returning result type R; you have to use Supplier<R> instead.
In essence, Java 8 lambdas have enriched what you can write, but the type system hasn't kept up
with the flexibility of the code. In many functional languages, you can write, for example, the
type (Integer, Double) => String, to represent what Java 8 calls BiFunction<Integer, Double,
String>, along with Integer => String to represent Function<Integer, String>, and even () =>
String to represent Supplier<String>. You can understand => as an infix version of Function,
BiFunction, Supplier, and the like. A simple extension to Java syntax for types would allow this,
resulting in more readable types analogously to what Scala provides, as discussed in chapter 15 .
Primitive specializations and generics
In Java all primitive types (int, for example) have a corresponding object type (here
java.lang.Integer); often we refer to these as unboxed and boxed types. Although this distinction
has the laudable aim of increasing runtime efficiency, the types can become confusing. For
example, why in Java 8 do we write Predicate<Apple> instead of Function<Apple, Boolean>? It
turns out that an object of type Predicate<Apple>, when called using the method test, returns a
primitive boolean.
By contrast, like all generics, a Function can only be parameterized by object types, which in the
case of Function<Apple, Boolean> is the object type Boolean, not the primitive type boolean.
Predicate<Apple> is therefore more efficient because it avoids boxing the boolean to make a
Boolean. This issue has led to the creation of multiple, similar interfaces such as
LongToIntFunction and BooleanSupplier, which add further conceptual overload. Another
 
Search WWH ::




Custom Search