当前位置: 代码迷 >> 综合 >> java8中预定义的函数式接口:Predicate、Consumer、Function等
  详细解决方案

java8中预定义的函数式接口:Predicate、Consumer、Function等

热度:44   发布时间:2024-01-14 05:06:33.0

上一篇中介绍的函数式接口的抽象方法是Lambda表达式的函数描述符,Lambda表达式需要有与之相匹配的函数式接口才能正常工作,那么在java8中,java的设计者为我们提供了哪些常用的函数式接口?

java.util.function.Predicate< T >

Predicate(谓词)函数式接口定义了一个test抽象方法,它接受泛型参数T并返回布尔值,其定义如下:

 
  1. @FunctionalInterface
  2. public interface Predicate<T>{
  3. boolean test(T t);
  4. }

谓词(predicate)在数学上常常用来代表一个类似函数的东西,它接受一个参数值,并返回true或false。

如果定义一个接受String对象的Lambda表达式,代码如下:

 
  1. //根据条件(行为)p过滤集合,符合条件p的加入过滤结果中
  2. public static <T> List<T> filter(List<T> list, Predicate<T> p) {
  3. List<T> results = new ArrayList<>();
  4. for(T s: list){
  5. if(p.test(s)){
  6. results.add(s);
  7. }
  8. }
  9. return results;
  10. }
  11. //Lambda表达式,判断非空
  12. Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
  13. //从集合中过滤出非空的字符串
  14. List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

java.util.function.Consumer< T >

Consumer翻译成中文是“消费者”的意思,如果从输入输出的角度来考虑,消费这一行为有输入但没有输出,因为输入的东西被消费掉了,对应到java里的函数就是一个有参数但没有返回值的函数,这个函数就是函数式接口Consumer的抽象方法,方法名叫accept,接收一个泛型参数T,无返回(void),定义如下:

 
  1. @FunctionalInterface
  2. public interface Consumer<T>{
  3. void accept(T t);
  4. }

应用如下:

 
  1. public static <T> void forEach(List<T> list, Consumer<T> c){
  2. for(T i: list){
  3. c.accept(i);
  4. }
  5. }
  6. //Lambda是函数式接口Consumer中抽象方法accept的实现
  7. forEach(Arrays.asList(1,2,3,4,5),(Integer i) -> System.out.println(i));

这里传递给forEach方法的第二个参数:Lambda表达式,就相当于实现了函数式接口Consumer中抽象方法accept.

java.util.function.Function< T, R >

定义:

 
  1. @FunctionalInterface
  2. public interface Function<T, R>{
  3. R apply(T t);
  4. }

从函数式接口Function的定义中可以看出,抽象方法apply是将泛型参数对象T转换成了泛型R对象,常用于将输入信息映射成另一种类型的输出。示例如下:

 
  1.  
  2. public static <T, R> List<R> map(List<T> list,Function<T, R> f) {
  3. List<R> result = new ArrayList<>();
  4. for(T s: list){
  5. result.add(f.apply(s));
  6. }
  7. return result;
  8. }
  9. //将输入的字符串集合映射成字符串长度的整形集合
  10. List<Integer> l = map(Arrays.asList("lambdas","in","action"),(String s) -> s.length());

同样,上面代码传递给map方法的第二个参数:lambda表达式,是Function方法apply的实现。

原始类型特化

前方介绍的三个泛型函数式接口: Predicate< T >、 Consumer< T >和Function< T,R >,只能绑定到引用类型,对于基本类型,如int、double等,虽然也能使用包装类型Intger\Double等来解决,但会涉及到自动装箱操作,当处理一定量的数据时,会带来性能问题,因此java8针对原始类型特化了一些函数式接口,专门用来处理原始类型数据,避免装箱与拆箱带来的性能问题。如:IntPredicate、LongPredicate等,其使用跟普通的函数式接口一样,只是针对了特定的数据类型。

java8还预定义了其它类型的函数式接口,如Supplier(与Consumer相对应)、UnaryOperator等,将它们总结如下:

函数式接口 函数描述符 原始类型特化
Predicate< T > T->boolean IntPredicate,LongPredicate, DoublePredicate
Consumer< T > T->void IntConsumer,LongConsumer, DoubleConsumer
Function< T,R > T->R IntFunction< R >,IntToDoubleFunction,IntToLongFunction,LongFunction< R >,LongToDoubleFunction,LongToIntFunction,DoubleFunction< R >,ToIntFunction< T >,ToDoubleFunction< T >,ToLongFunction< T >
Supplier< T > ()->T BooleanSupplier,IntSupplier, LongSupplier,DoubleSupplier
UnaryOperator< T > T->T IntUnaryOperator,LongUnaryOperator,DoubleUnaryOperator
BinaryOperator< T > (T,T)->T IntBinaryOperator,LongBinaryOperator,DoubleBinaryOperator
BiPredicate< L,R > (L,R)->boolean  
BiConsumer< T,U > (T,U)->void ObjIntConsumer< T >,ObjLongConsumer< T >,ObjDoubleConsumer< T >
BiFunction< T,U,R > (T,U)->R ToIntBiFunction< T,U >,ToLongBiFunction< T,U >,ToDoubleBiFunction< T,U >

一些常用的Lambda表达式与其对应的函数式接口应用举例:

使用案例 Lambda表达式 对应的函数式接口
布尔表达式 (List list) -> list.isEmpty() Predicate< List< String > >
创建对象 () -> new Apple(10) Supplier< Apple >
消费一个对象 (Apple a) -> System.out.println(a.getWeight()) Consumer< Apple >
从一个对象中选择/提取 (String s) -> s.length() Function< String, Integer >或ToIntFunction< String >
合并两个值 (int a, int b) -> a * b IntBinaryOperator
比较两个对象 (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()) Comparator< Apple >或BiFunction< Apple, Apple, Integer > 或 ToIntBiFunction< Apple, Apple >
  相关解决方案