函数式接口和lambda表达式
来源:互联网 发布:java中的类命名规范 编辑:程序博客网 时间:2024/05/29 12:49
函数式接口和lambda表达式
函数式接口(Functional Interface) :
任何接口,如果只包含唯一 一个抽象方法,那么它就是一个FI。(之前它们被称为 SAM类型,即 单抽象方法类型(Single Abstract Method))。接口中的方法默认就是public abstract的。
接口可能继承了一个 Object
已经提供的方法,比如 toString()
,equals( )
…这些都不属于函数式接口方法的范畴, 所以函数式接口中所说的方法不包括这些。例如下面FI接口也是一个函数式接口。
@FunctionalInterfaceInterface FI{ judge(int a); equals(); }
API作者们可以通过 @FunctionalInterface
注解来显式指定一个接口是函数式接口。加上这个注解,接口中函数式接口方法少于一个或者多余一个,编译器都会提示错误。
lambda表达式
lambda表达式是匿名方法 ,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。
// 1. 不需要参数,返回值为 5() -> 5// 2. 接收一个参数(数字类型),返回其2倍的值x -> 2 * x// 3. 接收2个int型整数,返回他们的和(int x, int y) -> x + y// 4. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)(String s) -> { System.out.print(s) }
lambda 表达式的语法由参数列表、箭头符号 ->
和函数体组成。函数体既可以是一个表达式,也可以是一个语句块。
假设我们想对一个List按字符串长度进行排序,那么在Java8之前,可以借助匿名内部类来实现:
List<String> words = Arrays.asList("apple", "banana", "pear");words.sort(new Comparator<String>() { @Override public int compare(String w1, String w2) { return Integer.compare(w1.length(), w2.length()); }});
上面的匿名内部类简直可以用丑陋来形容,唯一的一行逻辑被五行垃圾代码淹没。根据前面的定义(并查看Java源代码)可知,Comparator是个FI,所以,可以用Lambda表达式来实现:
words.sort((String w1, String w2) -> { return Integer.compare(w1.length(), w2.length());});
代码变短了好多!仔细观察就会发现,Lambda表达式,很像一个匿名的方法,只是圆括号内的参数列表和花括号内的代码被->分隔开了。垃圾代码写的越少,我们就有越多的时间去写真正的逻辑代码,不是吗?是的!圆括号里的参数类型是可以省略的:
words.sort((w1, w2) -> { return Integer.compare(w1.length(), w2.length());});
如果Lambda表达式的代码块只是return后面跟一个表达式,那么还可以进一步简化:
words.sort( (w1, w2) -> Integer.compare(w1.length(), w2.length()));
注意,表达式后面是没有分号的!如果只有一个参数,那么包围参数的圆括号可以省略:
words.forEach(word -> { System.out.println(word);});
如果表达式不需要参数呢?好吧,那也必须有圆括号,例如:
Executors.newSingleThreadExecutor().execute( () -> {/* do something. */} // Runnable);
怎么用Lambda表达式
既然Lambda表达式这么好用,那么,可以在哪些地方使用呢?如果你真正明白了什么是FI(很容易),应该立刻就能给出答案:任何可以接受一个FI实例的地方,都可以用Lambda表达式。比如,虽然上面给出的例子都是把Lambda表达式当作方法参数传递,可以接受FI作为参数的地方,都可以替换为Lambda表达式。
但实际上你也可以定义变量:
Runnable task = () -> { // do something};Comparator<String> cmp = (s1, s2) -> { return Integer.compare(s1.length(), s2.length());};
看两个例子:
使用已有的FI
JDK 1.8 新增加的函数接口:java.util.function 中Predicate 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。
eval( )方法的第二个参数是FI, 所以在这里可以用Lambda表达式.
import java.util.Arrays;import java.util.List;import java.util.function.Predicate;public class Java8Tester { public static void main(String args[]){ List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); System.out.println("输出所有数据:"); // Predicate<Integer> predicate = n -> true // n 是一个参数传递到 Predicate 接口的 test 方法 // n 如果存在则 test 方法返回 true // 传递参数 n eval(list, n->true); // Predicate<Integer> predicate1 = n -> n%2 == 0 // n 是一个参数传递到 Predicate 接口的 test 方法 // 如果 n%2 为 0 test 方法返回 true System.out.println("输出所有偶数:"); eval(list, n-> n%2 == 0 ); // Predicate<Integer> predicate2 = n -> n > 3 // n 是一个参数传递到 Predicate 接口的 test 方法 // 如果 n 大于 3 test 方法返回 true System.out.println("输出大于 3 的所有数字:"); eval(list, n-> n > 3 ); } public static void eval(List<Integer> list, Predicate<Integer> predicate) { for(Integer n: list) { if(predicate.test(n)) { System.out.print(n + " "); } } }}
输出
输出所有数据:1 2 3 4 5 6 7 8 9 输出所有偶数:2 4 6 8 输出大于 3 的所有数字:4 5 6 7 8 9
自定义FI
自定义一个FI,里面有一个add( ) 方法。 想不出什么好的例子,随便举个例子很简单能说明问题足矣
package com.java8;/** * Created by susq on 2017-6-20. */@FunctionalInterfacepublic interface Fitest { int add(int a, int b);}
package com.java8;/** * Created by susq on 2017-6-19. */public class LamJava8 { public static void main(String[] args) { int a = 2, b = 3; int result = addMethod( a, b, (c, d) -> { return c+d; } ); System.out.println( result ); } public static int addMethod(int a, int b, Fitest fi) { return fi.add(a, b); }}
输出:5
方法addMethod(int a, int b, Fitest fi) 第三个参数是我们自定义的FI, 因此这里可以用(c, d) -> { return c+d; }表达式,c, d是Fitest 中 add( ) 方法的两个参数, { return c+d; } 是add 方法的方法体。这里c, d不能写a, b,会提示变量重复定义编译错误。 因为(c, d) 实质为像(int c, int d) 一样的形参, int被我们省略了。
参考:http://www.tuicool.com/articles/beA7V3
http://lucida.me/blog/java-8-lambdas-insideout-language-features/
- Lambda表达式和函数式接口
- 函数式接口和lambda表达式
- lambda表达式:函数式接口
- Java8 新特性之一---------Lambda表达式和函数式接口
- Java——函数式接口和lambda表达式
- Java8的lambda表达式和函数式接口
- 函数式接口与 Lambda表达式
- Lambda表达式内置函数式接口
- java8 lambda表达式-函数接口
- Java 函数式接口、lambda表达式、函数引用
- java8函数式接口和Lambda表达式应用在javaFX中tableView自定义点击事件
- JDK 8.0 新特性——函数式接口和Lambda 表达式
- JDK 8.0 新特性——函数式接口和Lambda 表达式
- Java8 新特性-函数式接口,以及和Lambda表达式的关系
- java8新特性之函数式接口、lambda表达式、接口的默认方法、方法和构造函数的引用
- Java SE8函数式接口与Lambda表达式
- java8之Lambda表达式 2:内建函数式接口
- java8之Lambda表达式 2:内建函数式接口
- 在windows上安装和启动Elasticseach
- 树的非递归遍历
- 在 Ubuntu 11.10 上安装 Sun Grid Engine
- C++入门基本知识
- Java常见的几种排序方法
- 函数式接口和lambda表达式
- C++map如何按值排序
- LeetCode 重建BST
- Python快速入门(5)-列表与字典推导式
- java.io.StreamCorruptedException: invalid type code: AC
- 微信服务器和第三方服务器之间究竟是通过什么方式进行对话的?
- 操作系统概念(高等教育出版社,第七版)复习——第十一章:文件系统实现
- shiro从数据库中查询角色和权限
- HashMap死循环分析