Java8:函数式接口
来源:互联网 发布:php替换删除符号 编辑:程序博客网 时间:2024/06/08 15:56
在正式介绍Lambda表达式之前有一些概念是我们需要了解的。
函数式接口:仅仅声明了一个抽象方法的接口。
说明:函数式接口中除了抽象方法外,还可以有其他方法,但是必须被static或者default中修饰,且要有方法体。
Java API中常见的一些函数式接口
public interface Comparator<T> { // 抽象方法 int compare(T o1, T o2); // 除了抽象,默认或者静态方法外,函数式接口中还可以有Object类中public修饰的方法 boolean equals(Object obj); // 默认方法,含有方法体 default Comparator<T> reversed() { return Collections.reverseOrder(this); } // ...}
public interface Runnable{ void run();}
public interface Callable<V>{ V call();}
Java8自带了一些常用的函数式接口,放在 java.util.function包里。
为了避免装箱操作,装箱拆箱都有一定的性能损耗。对Predicate< T>和Function< T, R>等通用函数式接口的原始类型特化:IntPredicate、IntToLongFunction等。
函数描述符是什么?
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符。
例如,Runnable接口可以看作一个什么也不接受什么也不返回(void)的函数的签名,因为它只有一个叫作run的抽象方法,这个方法什么也不接受,什么也不返回(void)。
() -> void 代表了参数列表为空,且返回void的函数
(Apple,Apple) -> int 代表接受两个Apple作为参数且返回int的函数。
函数式接口可以干什么?
Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例,具体来说就是函数式接口的一个具体实现的实例。
当然匿名内部类也可以完成同样的事情,只不过比较笨拙。
举例:
// 1.使用LambdaRunnable r1 = () -> System.out.println("Hello World 1");new Thread(r1).start();// 2.使用匿名内部类Runnable r2 = new Runnable(){ public void run(){ System.out.println("Hello World 2"); }};new Thread(r2).start();
函数式接口和Lamdba表达式的关系?
只有在接受函数式接口的地方才可以使用Lamdba表达式。
Lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例。
使用函数式接口
函数式接口定义且只定义了一个抽象方法。函数式接口很有用,因为抽象方法的签名可以描述Lambda表达式的签名。函数式接口的抽象方法的签名称为函数描述符。所以为了应用不同的Lambda表达式,你需要一套能够描述常见函数描述符的函数式接口。
Java API中已经有了几个函数式接口,比如之前见到的Comparator、Runnable和Callable。
1. Predicate
java.util.function.Predicate< T > 接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。
函数描述符:(T)-> boolean
。
在你需要表示一个涉及类型T的布尔表达式时,就可以使用这个接口。比如,你可以定义一个接受String对象的Lambda表达式,如下所示。
@FunctionalInterfacepublic interface Predicate<T>{ boolean test(T t);}public static < T > List< T > filter(List< T> list, Predicate< T> p) { List< T> results = new ArrayList<>(); for(T s: list){ if(p.test(s)){ results.add(s); } } return results;}Predicate< String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();List< String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
2. Predicate
java.util.function.Consumer< T>定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void)。
函数描述符: (T)-> void
你如果需要访问类型T的对象,并对其执行某些操作,就可以使用这个接口。比如,你可以用它来创建一个forEach方法,接受一个Integers的列表,并对其中每个元素执行操作。在下面的代码中,你就可以使用这个forEach方法,并配合Lambda来打印列表中的所有元素。
@FunctionalInterfacepublic interface Consumer<T>{ void accept(T t);}public static <T> void forEach(List<T> list, Consumer<T> c){ for(T i: list){ c.accept(i); }}forEach(Arrays.asList(1,2,3,4,5),(Integer i) -> System.out.println(i));
3.Function
java.util.function.Function< T, R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。
函数描述符:(T) -> R
如果你需要定义一个Lambda,将输入对象的信息映射到输出,就可以使用这个接口(比如提取苹果的重量,或把字符串映射为它的长度)。在下面的代码中,我们向你展示如何利用它来创建一个map方法,以将一个String列表映射到包含每个String长度的Integer列表。
@FunctionalInterfacepublic interface Function<T, R>{ R apply(T t);}public static <T, R> List<R> map(List<T> list,Function<T, R> f) { List<R> result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result;}// [7, 2, 6]List<Integer> l = map(Arrays.asList("lambdas","in","action"),(String s) -> s.length());
关于接口中default和static方法的一些延伸:
问题:Java8中为什么要加入defalut方法呢?
答案:举例,在Java8之前,List接口中并没有stream()或者 parallelStream()方法,它实现的collection接口也没有,因为当初设计接口的时候还没有想到这些方法,最简单的方案就是Java8的设计者把steam方法加入collection中。可是如果这样做的话对于用户来说就是噩梦了,因为给接口加入一个方法,意味所有实体类都必须为其提供一个实现。
Java8中引入了支持defalut修饰的方法,这样方法就有了默认实现而不用实体类去实现这个方法。
- Java8:函数式接口
- java8内置函数式接口
- JAVA8 函数式接口介绍
- Java8内置函数式接口
- Java8之函数式接口
- java8提供的简单函数式接口
- java8 四个核心函数式接口
- java8:@FunctionalInterface函数式接口注解
- Java8新特性函数式接口
- Java8中的函数式接口及使用
- Java8的四大核心函数式接口
- java8 函数式接口(FunctionalInterface) [一]
- java8 函数式接口(FunctionalInterface) [二]
- Java8 新特性 函数式接口
- 深入学习java8二(函数式接口)
- Java8的四大核心函数式接口
- Java8自定义带泛型的函数式接口
- Java8-函数式接口理解及测试
- Rx系列学习之旅(三)--Base基类的实现
- scanf函数返回值问题
- 《统计学习方法》第一章习题
- Android Studio 进行NDK开发入门
- HTTP状态码
- Java8:函数式接口
- Eclipse 如何添加Window Builder插件?
- 图的遍历
- 笔记三---jni库的加载
- 基于伪标记的半监督学习方法
- ReactNative 移植Android项目
- sql语句拼装,需要if判断时一个小技巧
- GCD之死锁体会
- android弹出消息框、输入框、选择框、日期选择