函数式接口(Functional Interface)
简介
它是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
如定义了一个函数式接口如下:
public class GreetingDemo {
@FunctionalInterface
interface GreetingInterface {
void sayMessage(String message);
}
public static void main(String[] args) {
GreetingInterface greetingInterface = message -> {
System.out.println("Hello " + message);
};
greetingInterface.sayMessage("Tom");
}
}
输出即为:Hello Tom
function包下的函数式接口
java.util.function 它包含了很多类,用来支持 Java的 函数式编程,该包中的函数式接口有
序号 | 接口 & 描述 |
1 | BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果 |
2 | BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果 |
3 | BinaryOperator 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
4 | BiPredicate<T,U> 代表了一个两个参数的boolean值方法 |
5 | BooleanSupplier 代表了boolean值结果的提供方 |
6 | Consumer 代表了接受一个输入参数并且无返回的操作 |
7 | DoubleBinaryOperator 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
8 | DoubleConsumer 代表一个接受double值参数的操作,并且不返回结果。 |
9 | DoubleFunction 代表接受一个double值参数的方法,并且返回结果 |
10 | DoublePredicate 代表一个拥有double值参数的boolean值方法 |
11 | DoubleSupplier 代表一个double值结构的提供方 |
12 | DoubleToIntFunction 接受一个double类型输入,返回一个int类型结果。 |
13 | DoubleToLongFunction 接受一个double类型输入,返回一个long类型结果 |
14 | DoubleUnaryOperator 接受一个参数同为类型double,返回值类型也为double 。 |
15 | Function<T,R> 接受一个输入参数,返回一个结果。 |
16 | IntBinaryOperator 接受两个参数同为类型int,返回值类型也为int 。 |
17 | IntConsumer 接受一个int类型的输入参数,无返回值 。 |
18 | IntFunction 接受一个int类型输入参数,返回一个结果 。 |
19 | IntPredicate :接受一个int输入参数,返回一个布尔值的结果。 |
20 | IntSupplier 无参数,返回一个int类型结果。 |
21 | IntToDoubleFunction 接受一个int类型输入,返回一个double类型结果 。 |
22 | IntToLongFunction 接受一个int类型输入,返回一个long类型结果。 |
23 | IntUnaryOperator 接受一个参数同为类型int,返回值类型也为int 。 |
24 | LongBinaryOperator 接受两个参数同为类型long,返回值类型也为long。 |
25 | LongConsumer 接受一个long类型的输入参数,无返回值。 |
26 | LongFunction 接受一个long类型输入参数,返回一个结果。 |
27 | LongPredicate R接受一个long输入参数,返回一个布尔值类型结果。 |
28 | LongSupplier 无参数,返回一个结果long类型的值。 |
29 | LongToDoubleFunction 接受一个long类型输入,返回一个double类型结果。 |
30 | LongToIntFunction 接受一个long类型输入,返回一个int类型结果。 |
31 | LongUnaryOperator 接受一个参数同为类型long,返回值类型也为long。 |
32 | ObjDoubleConsumer 接受一个object类型和一个double类型的输入参数,无返回值。 |
33 | ObjIntConsumer 接受一个object类型和一个int类型的输入参数,无返回值。 |
34 | ObjLongConsumer 接受一个object类型和一个long类型的输入参数,无返回值。 |
35 | Predicate 接受一个输入参数,返回一个布尔值结果。 |
36 | Supplier 无参数,返回一个结果。 |
37 | ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个double类型结果 |
38 | ToDoubleFunction 接受一个输入参数,返回一个double类型结果 |
39 | ToIntBiFunction<T,U> 接受两个输入参数,返回一个int类型结果。 |
40 | ToIntFunction 接受一个输入参数,返回一个int类型结果。 |
41 | ToLongBiFunction<T,U> 接受两个输入参数,返回一个long类型结果。 |
42 | ToLongFunction 接受一个输入参数,返回一个long类型结果。 |
43 | UnaryOperator 接受一个参数为类型T,返回值类型也为T。 |
几种常见的函数式接口
Consumer
Represents an operation that accepts a single input argument and returns no result.
源码如下,
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
使用方法示例如下,
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> f = System.out::println;
Consumer<String> f2 = n -> System.out.println(n + "F2");
// 执行完f后再执行f2的Accept方法
f.andThen(f2).accept("test");
// 连续执行f2的Accept方法
f2.andThen(f2).andThen(f2).accept("test1");
BiConsumer<String, String> f3 = (x, y) -> System.out.println(x + "," + y);
f3.accept("x=5", "y=6");
}
}
输出结果如下,
Function
Represents a function that accepts one argument and produces a result.
源码如下,
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
使用示例如下,
import java.util.function.BiFunction;
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
Function<Integer, Integer> f = s -> ++s;
Function<Integer, Integer> g = s -> s * 2;
// 先执行g再执行f,3*2 +1 = 7
System.out.println(f.compose(g).apply(3));
// 先执行f再执行g,(3+1)*2 = 8
System.out.println(f.andThen(g).apply(3));
// identify方法会返回一个不进行处理的Function,即输出和输入值相等
System.out.println(Function.identity().apply("a"));
// 泛型中第一个第二个为输入类型,第三个为输出类型
BiFunction<String, String, Integer> biFunction = (x, y) -> Integer.parseInt(x) + Integer.parseInt(y);
System.out.println(biFunction.apply("51", "94"));
}
}
输出结果如下,
Predicate
Represents a predicate (boolean-valued function) of one argument.
源码如下,
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
使用示例如下,
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Assert;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class PredicateDemo {
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
static class Gift {
private String name;
private int price;
}
public static void main(String[] args) {
Predicate<String> p = "test"::equals;
Predicate<String> g = o -> o.startsWith("t");
// negate:用于对原来的Predicate做取反处理;
Assert.assertFalse(p.negate().test("test"));
// 针对同一个输入值,多个Predicate均返回true时返回true,否则返回false
Assert.assertTrue(p.and(g).test("test"));
// 针对同一个输入值,多个Predicate只要有一个返回true则返回true,否则返回false
Assert.assertTrue(p.or(g).test("test"));
Gift exceptGift = new Gift("Ps4", 1000);
Predicate<Gift> predicate = Predicate.isEqual(exceptGift);
System.out.println(
Stream.of(
Gift.builder().name("egg").price(1).build(),
Gift.builder().name("apple").price(3).build(),
Gift.builder().name("Ps4").price(1000).build(),
Gift.builder().name("banana").price(2).build(),
Gift.builder().name("Ps4").price(1000).build(),
Gift.builder().name("belt").price(20).build(),
Gift.builder().name("Ps4").price(1000).build(),
Gift.builder().name("book").price(50).build()
).filter(predicate).count()
);
}
}
Supplier
Represents a supplier of results.
源码如下,
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Supplier看起来应该是最简单的一个函数式接口,下面看看怎么用它,
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.function.Supplier;
public class SupplierDemo {
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
static class Product {
private String name;
private String expiration = currentDateTime();
}
public static void main(String[] args) {
Supplier<Product> supplier = Product::new;
System.out.println(supplier.get().expiration);
}
private static String currentDateTime() {
long millis = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
return format.format(millis);
}
}
输出结果如下,
总结
上面介绍了几个简单的函数式接口以及该函数式接口如何使用,引入函数式接口在一定程度上可以提高编码效率,使用过程也更加简便。需要开发者自行熟悉。
如果感兴趣的可以思考一下函数式接口在效率上是否更快呢?
可以先去查看编译后的class文件,以上面的ConsumerDemo为例,对应的ConsumerDemo.class文件代码如下,
package com.hust.zhang.functional;
import java.io.PrintStream;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class ConsumerDemo {
public ConsumerDemo() {
}
public static void main(String[] args) {
PrintStream var10000 = System.out;
Consumer<String> f = var10000::println;
Consumer<String> f2 = (n) -> {
System.out.println(n + "F2");
};
f.andThen(f2).accept("test");
f2.andThen(f2).andThen(f2).accept("test1");
BiConsumer<String, String> f3 = (x, y) -> {
System.out.println(x + "," + y);
};
f3.accept("x=5", "y=6");
}
}
再使用javap -c ConsumerDemo.class反编译class文件看看源码如下,
public class com.hust.zhang.functional.ConsumerDemo {
public com.hust.zhang.functional.ConsumerDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: dup
4: invokevirtual #3 // Method java/lang/Object.getClass:()Ljava/lang/Class;
7: pop
8: invokedynamic #4, 0 // InvokeDynamic #0:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;
13: astore_1
14: invokedynamic #5, 0 // InvokeDynamic #1:accept:()Ljava/util/function/Consumer;
19: astore_2
20: aload_1
21: aload_2
22: invokeinterface #6, 2 // InterfaceMethod java/util/function/Consumer.andThen:(Ljava/util/function/Consumer;)Ljava/util/function/Consumer;
27: ldc #7 // String test
29: invokeinterface #8, 2 // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
34: aload_2
35: aload_2
36: invokeinterface #6, 2 // InterfaceMethod java/util/function/Consumer.andThen:(Ljava/util/function/Consumer;)Ljava/util/function/Consumer;
41: aload_2
42: invokeinterface #6, 2 // InterfaceMethod java/util/function/Consumer.andThen:(Ljava/util/function/Consumer;)Ljava/util/function/Consumer;
47: ldc #9 // String test1
49: invokeinterface #8, 2 // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
54: invokedynamic #10, 0 // InvokeDynamic #2:accept:()Ljava/util/function/BiConsumer;
59: astore_3
60: aload_3
61: ldc #11 // String x=5
63: ldc #12 // String y=6
65: invokeinterface #13, 3 // InterfaceMethod java/util/function/BiConsumer.accept:(Ljava/lang/Object;Ljava/lang/Object;)V
70: return
}
参考链接:https://www.runoob.com/java/java8-functional-interfaces.html