文章目录
- 函数接口Function
- 函数式接口只允许有一个抽像方法
- 通过Lambda表达式实现接口
- @FunctionalInterface注解
- 构建一个函数式接口
- 使用自己创建的函数式接口
- JDK中的函数式接口
- Function函数
- 最常用的Function<T,R>使用
- apply(T t)
- andThen(Function<? super R,? extends V> after)
- compose(Function<? super V,? extends T> before)
- 最常用的BiFunction<T, U, R>使用
- apply(T t, U u)
- andThen(Function<? super R,? extends V> after)
- 在Stream流中的用法
- 总结
函数接口Function
在Java 8 中引入了函数式接口(Functional Internal),函数式接口的特征是它是只有一个抽象方法的接口。
- 是个接口
- 只有一个抽象方法
函数式接口只允许有一个抽像方法
函数式接口是 Java 8 中的新增功能。通常,函数式接口中的方法只能有一个抽象方法,这些函数式接口也称为单抽象方法接口。但是除了一个抽象方法之外,函数式接口还可以具有静态方法和继承自object的方法:
- 默认方法(default methods),只能有一个
- 静态方法(static methods),可以有多个
- 继承自object 的public方法,可以有多个
通过Lambda表达式实现接口
在 Java 中,lambda 表达式可用于表示实现函数式接口的实例。例如,Comparator 接口就是一个函数式接口。
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
// equals继承自object,所以并不违反函数接口单抽象方法的原则
boolean equals(Object obj);
// 其他都是default methods
}
虽然Comparator有两个抽象方法,但是其中equals继承自Object类,所以他并不算违反单抽象方法的原则。除了这两个抽象方法外,其他都是default method。所以Comparator就是一个函数式的接口 。
在Java中使用Lambda表达式实现Comparator接口:
//Compare by Id
Comparator<Employee> compareById = Comparator.comparing(e -> e.getId());
Comparator<Employee> compareByFirstName = Comparator.comparing(e -> e.getFirstName());
其中e -> e.getId() 和 e->e.getFirstName() 是个函数,Comparator.comparing()接受这个函数,返回的值是Comparator接口。
@FunctionalInterface注解
Java 8 引入了注释 @FunctionalInterface,用于将接口标记为函数式接口。此注释的主要用途是当接口违反一个抽象方法的契约时,产生编译器级错误。但是注意:该注解并不是必须的。
如果接口有一个抽象方法并且没有 @FunctionalInterface 注解,那么该接口仍然是一个函数式接口,并且可以作为 lambda 表达式的目标类型。注释的存在用于防止我们无意中将函数接口更改为非函数接口,因为编译器会捕获它。
构建一个函数式接口
@FunctionalInterface
public interface MyFirstFunctionalInterface
{
public void firstWork();
}
如果我们再添加一个抽象方法,可以看到错误提示。
使用自己创建的函数式接口
定义好函数接口,其中泛型T作为参数输入类型,R作为返回值类型限定:
@FunctionalInterface
public interface MySecondFunctionalInterface<T, R> {
R doSomething(T name);
}
使用:
@Test
public void testSecondFunction() {
MySecondFunctionalInterface<String, Integer> inputLength = String::length;
MySecondFunctionalInterface<String, String> addGreeting = s -> "welcome " + s;
MySecondFunctionalInterface<String, String> revertInput = StrUtil::reverse;
System.out.println(inputLength.doSomething("hello world"));
System.out.println(addGreeting.doSomething("sea"));
System.out.println(revertInput.doSomething("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
// 输出信息
// 11
// welcome sea
// ZYXWVUTSRQPONMLKJIHGFEDCBA
}
JDK中的函数式接口
在java中使用比较广泛的函数接口如下:
- Function:仅包含apply()方法
- Runnable:仅包含 run() 方法
- Comparable:仅包含 compareTo () 方法。
- ActionListener:仅包含 actionPerformed ()方法。
- Callable:仅包含 call () 方法。
- Predicate:一个接受一个参数并返回 true 或 false的布尔值函数。
- BiPredicate:带有两个参数的谓词。
- Consumer:一种接受一个参数、对其进行操作且不返回结果的操作。
- BiConsumer:带有两个参数的消费者。
- Supplier:一个返回值的供应者。 Function<T, R>:接受类型为 T的参数并返回类型为 R 的结果。
- BiFunction<T, U, R>:接受类型为 T 和 U 的两个参数并返回类型为 R 的结果。
Function函数
序号 | 接口 | 描述 |
---|---|---|
1 | Function<T, R> | 接收一个参数并返回结果的函数 |
2 | BiFunction<T,U.R> | 接受两个参数并返回结果的函数 |
3 | DoubleFunction | 接收一个 double 类型的参数并返回结果的函数 |
4 | DoubleToIntFunction | 接收一个 double 类型的参数并返回 int 结果的函数 |
5 | DoubleToLongFunction | 接收一个 double 类型的参数并返回 long 结果的函数 |
6 | IntFunction | 接收一个 int 类型的参数并返回结果的函数 |
7 | IntToDoubleFunction | 接收一个 int 类型的参数并返回 double 结果的函数 |
8 | IntToLongFunction | 接收一个 Int 类型的参数并返回 long 结果的函数 |
9 | LongFunction | 接收一个 long 类型的参数并返回结果的函数 |
10 | LongToDoubleFunction | 接收一个 long 类型的参数并返回 double 结果的函数 |
11 | LongToIntFunction | 接收一个 long 类型的参数并返回 int 结果的函数 |
12 | ToDoubleBiFunction<T,U> | 接收两个参数并返回 double 结果的函数 |
13 | ToDoubleFunction | 接收一个参数并返回 double 结果的函数 |
14 | ToIntBiFunction<T, U> | 接收两个参数并返回 int 结果的函数 |
15 | ToIntFunction | 接收一个参数并返回 Int 结果的函数 |
16 | ToLongBiFunction<T, U> | 接收两个参数并返回 long 结果的函数 |
17 | ToLongFunction | 接收一个参数并返回 long 结果的函数 |
最常用的Function<T,R>使用
apply(T t)
Function<String, String> function = a -> a + " Jack!";
System.out.println(function.apply("Hello")); // Hello Jack!
andThen(Function<? super R,? extends V> after)
Function<String, String> function = a -> a + " Jack!";
Function<String, String> function1 = a -> a + " Bob!";
String greet = function.andThen(function1).apply("Hello");
System.out.println(greet); // Hello Jack! Bob!
compose(Function<? super V,? extends T> before)
Function<String, String> function = a -> a + " Jack!";
Function<String, String> function1 = a -> a + " Bob!";
String greet = function.compose(function1).apply("Hello");
System.out.println(greet); // Hello Bob! Jack!
最常用的BiFunction<T, U, R>使用
与上面不同的是,这个可以传递两个参数
apply(T t, U u)
BiFunction<String, String, String> biFunction = (a, b) -> a + b;
System.out.println(biFunction.apply("Hello ", "Jack!")); // Hello Jack!
andThen(Function<? super R,? extends V> after)
BiFunction<String, String, String> biFunction = (a, b) -> a + b;
Function<String, String> function = (a) -> a + "!!!";
System.out.println(biFunction.andThen(function).apply("Hello", " Jack")); // Hello Jack!!!
在Stream流中的用法
Stream流中map接受一个Function参数如下:
代码:
@Test
public void testFunctionInStream() {
List<PredicateDemo.People> people = new PredicateDemo().mockPeopleList();
people.stream().map(x -> x.getName()).forEach(System.out::println);
}
可以输出每个人的名字,亦或将每个名字组装成一个list:
@Test
public void testFunctionInStream() {
List<PredicateDemo.People> people = new PredicateDemo().mockPeopleList();
people.stream().map(x -> x.getName()).collect(Collectors.toList());
}
还可以使用Comparator将用户按照名字进行排序,如下:
@Test
public void testFunctionInStream() {
List<PredicateDemo.People> people = new PredicateDemo().mockPeopleList();
people.stream().sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).forEach(System.out::println);
}
总结
以上介绍了如何在 Java 中创建和管理函数式接口。我们了解到函数式接口只有一个抽象方法,并且可以通过 lambda 表达式来实现。还分享了 JDK 提供的现有函数式接口,最后通过例子了解了如何创建和使用函数式接口。