编程进阶:初探Java的函数式编程及内置函数式接口例解

实践进阶:初探Java的函数式接口及其内置函数式接口例解

编程进阶:初探Java的函数式编程及内置函数式接口例解

Java函数式接口这个术语是在Java 8中引入的。Java中的函数式接口是一个只包含一个抽象(未实现)方法的接口。 除了单个未实现的方法之外,函数式接口还可以包含具有实现的默认和静态方法。函数式接口,有时也被称为SAM类型,意思为单抽象方法(Single Abstract Method)

下面是个函数式接口的示例:

public interface MyFunctionalInterface {
public void execute();
}

以上算作Java中的函数式接口,因为它只包含一个方法,并且该方法没有实现。 通常,Java接口不包含它声明的方法的实现,但它可以包含默认方法或静态方法中的实现。 下面是Java函数式接口的另一个示例,其中包含一些方法的实现:

public interface MyFunctionalInterface2{
public void execute();
public default void print(String text) {
System.out.println(text);
}
public static void print(String text, PrintWriter writer) throws IOException {
writer.write(text);
}
}

上面的接口仍然算作Java中的函数式接口,因为它只包含一个未实现的方法。

至此,你因该理解了所谓的"函数式接口"了。那么,继续…

1. 函数式接口实现

函数式接口可由Lambda表达式实现.

Java函数式接口可以由Java Lambda表达式实现。下面是一个实现本文开始定义的函数式接口MyFunctionalInterface的示例:

MyFunctionalInterface lambda = () -> {
System.out.println("Executing...");
}

一个lambda表达式实现来自Java接口的单个方法。 为了知道lambda表达式实现的是什么方法,接口只能包含一个未实现的方法。换句话说,接口必须是Java函数式接口。

其实,lambda表达式本质上就是一个匿名(即未命名)的方法。但这个方法不是独立执行的,而是用于实现函数式接口定义的另一个方法。因此,lambda表达式会导致产生一个匿名类。Lambda表达式也常称作闭包。

在实际应用中要特别注意,lambda表达式只能用于其目标类型已被指定的上下文中(也就是根据其特性,可以使用的地方或业务场景下)。

这里不会更详细地解释Java lambda表达式。了解有关lambda表达式的更多信息,将陆续发表一些相关教程,先期待着吧^_^。

2.Java中内置函数式接口

Java包含一组为常见案例设计的函数式接口,因此,您不必为每个小案例创建自己的功能接口。 在下面的部分中,我将介绍Java中的一些内置功能接口。

2.1 Function接口

Java 的Function接口(java.util.function.Function)是Java中最核心的函数式接口之一。 Function接口表示一个函数(方法),它接受单个参数并返回单个值。 以下是Function接口定义的外观:

public interface Function<T,R> {
public <R> apply(T parameter);
}

除了上面列出的方法之外,Function接口实际上还包含一些额外的方法,但由于它们都带有默认实现,因此您不必实现这些额外的方法。 额外的方法将在后面的章节中解释。

实现Function接口必须实现的唯一方法是apply()方法。 这是一个Function实现示例:

public class AddThree implements Function<Long, Long> {
@Override
public Long apply(Long aLong) {
return aLong + 3;
}
}

此Function实现实现了apply()方法,因此它接收Long型参数,并返回Long型值。 以下是使用上述AddThree类的示例:

Function<Long, Long> adder = new AddThree();
Long result = adder.apply((long) 4);
System.out.println("result = " + result);

首先,此示例创建一个新的AddThree实例,并将其分配给Function变量。 其次,该示例在AddThree实例上调用apply()方法。 第三,该示例打印出结果(即7)。

您还可以使用Java lambda表达式实现Function接口。看起来就像下面这样:

Function<Long, Long> adderLambda = (value) -> value + 3;
Long resultLambda = adder.apply((long) 8);
System.out.println("resultLambda = " + resultLambda);

如您所见,函数式接口实现,现在是在adderLambda变量的声明中内联的,而不是在单独的类中。 这虽有点短,但可以直接在上面的代码中看到它正在做什么。

2.2. Predicate接口

Java的Predicate接口,即java.util.function.Predicate表示一个简单的函数,它将单个值作为参数,并返回true或false。 以下是Predicate函数式接口定义的外观:

public interface Predicate {
boolean test(T t);
}

Predicate接口包含的方法多于test()方法,但其余方法是默认或静态方法,您不必实现这些方法。

您可以使用类来实现Predicate接口,如下所示:

public class CheckForNull implements Predicate {
@Override
public boolean test(Object o) {
return o != null;
}
}

您还可用Lambda表达式实现Java的Predicate接口。 以下是使用Java lambda表达式实现Predicate接口的示例:

Predicate predicate = (value) -> value != null;

Predicate接口的lambda实现与上面使用类的实现有相同效果。

2.3. UnaryOperator接口(一元运算符)

Java的UnaryOperator接口是一个功能接口,表示接收单个参数并返回相同类型参数的操作。 以下是Java的UnaryOperator实现的示例:

UnaryOperator<Person> unaryOperator =
(person) -> { person.name = "New Name"; return person; };

UnaryOperator接口可用于表示将特定对象作为参数,修改该对象并再次返回的操作——可能作为功能流处理链的一部分。

2.4. BinaryOperator接口(二元运算符)

Java的BinaryOperator接口是一个函数式接口,表示一个操作,它接受两个参数并返回一个值。参数和返回类型必须属于同一类型。

Java的BinaryOperator接口在实现对两个相同类型的元素进行求和、相减、除、乘等等的函数时非常有用,并返回相同类型的第三个元素。

以下是BinaryOperator接口的示例实现:

BinaryOperator<MyValue> binaryOperator =
(value1, value2) -> { value1.add(value2); return value1; };

2.5. Supplier接口

Java的Supplier接口是一个函数式接口,表示提供某些类型值的函数。Supplier接口也可以被视为工厂接口。 以下是Java Supplier接口的示例实现:

Supplier<Integer> supplier = () -> new Integer((int) (Math.random() * 1000D));

此Java的Supplier实现返回一个新的Integer实例,其随机值介于0和1000之间。

Java的Consumer接口是一个函数式接口,表示在不返回任何值的情况下使用值的函数。Java的Consumer实现可以打印出一个值,或者将其写入文件,或者通过网络传输等。以下是Java的Consumer接口的示例实现:

Consumer<Integer> consumer = (value) -> System.out.println(value);

此Java的Consumer实现,其功能就是将作为参数传递的值打印到System.out上。

好了,本文就写这些了,应该能助你理解和掌握基本的Java函数式编程了。


相关推荐