Home > Articles > Programming > Java

  • Print
  • + Share This
This chapter is from the book

3.3. Choosing a Functional Interface

In most functional programming languages, function types are structural. To specify a function that maps two strings to an integer, you use a type that looks something like Function2<String, String, Integer> or (String, String) -> int. In Java, you instead declare the intent of the function, using a functional interface such as Comparator<String>. In the theory of programming languages this is called nominal typing.

Of course, there are many situations where you want to accept “any function” without particular semantics. There are a number of generic function types for that purpose (see Table 3-1), and it’s a very good idea to use one of them when you can.

Table 3-1 Common Functional Interfaces

Functional Interface

Parameter Types

Return Type

Abstract Method Name

Description

Other Methods

Runnable

none

void

run

Runs an action without arguments or return value

Supplier<T>

none

T

get

Supplies a value of type T

Consumer<T>

T

void

accept

Consumes a value of type T

chain

BiConsumer<T, U>

T, U

void

accept

Consumes values of types T and U

chain

Function<T, R>

T

R

apply

A function with argument of type T

compose, andThen, identity

BiFunction<T, U, R>

T, U

R

apply

A function with arguments of types T and U

andThen

UnaryOperator<T>

T

T

apply

A unary operator on the type T

compose, andThen, identity

BinaryOperator<T>

T, T

T

apply

A binary operator on the type T

andThen

Predicate<T>

T

boolean

test

A Boolean-valued function

and, or, negate, isEqual

BiPredicate<T, U>

T, U

boolean

test

A Boolean-valued function with two arguments

and, or, negate

For example, suppose you write a method to process files that match a certain criterion. Should you use the descriptive java.io.FileFilter class or a Predicate<File>? I strongly recommend that you use the standard Predicate<File>. The only reason not to do so would be if you already have many useful methods producing FileFilter instances.

Consider another example. We want to transform images, applying a Color -> Color function to each pixel. For example, the brightened image in Figure 3-1 is obtained by calling

Image brightenedImage = transform(image, Color::brighter);
Figure 3-1

Figure 3-1 The original and transformed image

There is a standard functional interface for this purpose: UnaryOperator<Color>. That is a good choice, and there is no need to come up with a ColorTransformer interface.

Here is the implementation of the transform method. Note the call to the apply method.

public static Image transform(Image in, UnaryOperator<Color> f) {
   int width = (int) in.getWidth();
   int height = (int) in.getHeight();
   WritableImage out = new WritableImage(width, height);
   for (int x = 0; x < width; x++)
      for (int y = 0; y < height; y++)
         out.getPixelWriter().setColor(x, y, 
            f.apply(in.getPixelReader().getColor(x, y)));
   return out;
}

Table 3-2 lists the 34 available specializations for primitive types int, long, and double. Use the specializations when you can to reduce autoboxing.

Table 3-2 Functional Interfaces for Primitive Types: p, q is int, long, double; P, Q is Int, Long, Double

Functional Interface

Parameter Types

Return Type

Abstract Method Name

BooleanSupplier

none

boolean

getAsBoolean

PSupplier

none

p

getAsP

PConsumer

p

void

accept

ObjPConsumer<T>

T, p

void

accept

PFunction<T>

p

T

apply

PToQFunction

p

q

applyAsQ

ToPFunction<T>

T

p

applyAsP

ToPBiFunction<T, U>

T, U

p

applyAsP

PUnaryOperator

p

p

applyAsP

PBinaryOperator

p, p

p

applyAsP

PPredicate

p

boolean

test

Sometimes, you need to supply your own functional interface because there is nothing in the standard library that works for you. Suppose you want to modify colors in an image, allowing users to specify a function (int, int, Color) -> Color that computes a new color depending on the (x, y) location in the image. In that case, you can define your own interface:

@FunctionalInterface
public interface ColorTransformer {
   Color apply(int x, int y, Color colorAtXY);  
}
  • + Share This
  • 🔖 Save To Your Account