What
“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。*Lambda表达式可以表示闭包*(注意和数学传统意义上的不同)。
WHY
- 使用Lambda表达式可以使代码变得更加紧凑
- 修改方法的能力,函数中可以接受以函数为单元的参数
HOW
先决条件
Lambda表达式只能出现在目标类型为函数式接口的上下文中
使用环境:
函数式接口(Functional Interface)
定义的一个接口,接口里面必须有且只有一个抽象方法,这样的接口就成为函数式接口。在可以使用lambda表达式的地方,方法声明时必须包含一个函数式的接口。任何函数式接口都可以使用Lambda表达式替换。
Lambda表达式的语法
1.基本语法
(parameters) -> expression 或 (parameters)->{statements;}
参数 -> 带返回值的表达式/无返回值的陈述
2.简单例子:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
方法引用
- 静态方法引用:
ClassName::methodName
- 实例上的方法引用:
instanceReference::methodName
- 超类上的实例方法引用:
super::methodName
- 类型上的实例方法引用:
ClassName::methodName
- 构造方法引用:
Class::new
- 数组构造方法引用:
TypeName[] :: new
Java提供的SAM(SingleAbstractMethod)接口
Java8中新增加了一个包:java.util.function,它里面包含了常用的函数式接口,在参数为这些接口的地方可以直接使用lambda表达式例如:
Predicate<T>——接收T对象并返回boolean
Consumer<T>——接收T对象,不返回值
Function<T, R>——接收T对象,返回R对象
Supplier<T>——提供T对象(例如工厂),不接收值
UnaryOperator<T>——接收T对象,返回T对象
BinaryOperator<T>——接收两个T对象,返回T对象
Samples
自定义SAM接口,使用lambda表达式
public class TestLambda {
public static void main(String[] args){
//以Lambda表达式方式传入匿名内部对象
doSth((int x,int y) -> {System.out.println(x+y);return x+y;}, 10, 20);
}
public static void doSth(Add add, int x, int y) {
add.add(x,y);
}
}
//SAM接口
interface Add{
int add(int x,int y);
}
Runnable的Lambda用法
public class TestLambda {
public static void main(String[] args){
//通常用法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Original123456");
System.out.println("Original678910");
}
}).start();
//Lambda用法
new Thread(() -> {System.out.println("Lambda123456");
System.out.println("Lambda678910");}).start();
}
}
使用Comparator
/**
* 使用Lambda进行排序
*/
public static void sort() {
String[] strs = {"abc", "def", "acd", "bcf","cdf"};
Comparator<String> sort = (String s1, String s2) -> (s1.compareTo(s2));
Arrays.sort(strs, sort);
for (String a : strs)
System.out.println(a);
}
Stream
What
支持顺序和并行操作的一系列元素,就是Java8提供对于元素集合统一、快速、并行操作的一种方式,可以支持顺序和并行对元素操作的元素集合
Why
- 提供了操作数据的接口,让数据操作更容易和更快
- 使用Stream,能对集合元素进行过滤、映射、排序、去重等操作
How
- 通过
Stream
接口的静态方法(java8中接口中可以存在静态方法)。 - 通过
Collection
接口默认方法(默认方法:Default method
,java8新特性),stream()
,可以把一个Collection
对象转成Stream
。
使用示例
1.使用Lambda表达式迭代数据
- 先建立
Book
相关Bean类
public class Book {
private String name;
private double price;
private String author;
private int level;
public Book(String name, double price, String author, int level) {
this.name = name;
this.price = price;
this.author = author;
this.level = level;
}
//省略getter and setter
...
}
- 使用Lambda表达式迭代数据
public static void iterateData(){
List<Book> listData = new LinkedList<>();
listData.add(new Book("book1",1.2,"author1",1));
listData.add(new Book("book2",1.5,"author2",2));
listData.add(new Book("book3",1.7,"author3",1));
listData.add(new Book("book4",2.2,"author4",2));
listData.add(new Book("book5",3.2,"author5",1));
listData.add(new Book("book6",4.2,"author6",2));
listData.add(new Book("book7",5.2,"author7",1));
listData.forEach((b)-> System.out.println(b.getAuthor()+":"+b.getName()));
}
2. 使用Stream与filter(过滤器)
/**
* 过滤数据
*/
public static void filterData(){
List<Book> listData = new LinkedList<>();
listData.add(new Book("book1",1.2,"author1",1));
listData.add(new Book("book2",1.5,"author2",2));
listData.add(new Book("book3",1.7,"author3",1));
listData.add(new Book("book4",2.2,"author4",2));
listData.add(new Book("book5",3.2,"author5",1));
listData.add(new Book("book6",4.2,"author6",2));
listData.add(new Book("book7",5.2,"author7",1));
//定义过滤器
Predicate<Book> priceFilter= (p) -> (p.getPrice()>1.3);
Predicate<Book> levelFilter= (p) -> (p.getLevel()>1);
listData.stream()
.filter(priceFilter)//添加过滤器
.filter(levelFilter)
.sorted((p, p2) -> p.getPrice() > p2.getPrice()? 1 : p.getPrice() == p2.getPrice() ? 0 : -1 ) //增加排序
.limit(2) //使用limit可以限制结果的个数
.forEach((p) -> System.out.println(p.getName()+"--"+p.getPrice()+"--"+p.getLevel()));
}
3.求最大最小值
//求最小的数据
Book bookMin = listData.stream()
.min((p1, p2) -> (int) (p1.getPrice() - p2.getPrice()))
.get();
System.out.println(bookMin.getName()+bookMin.getPrice());
//求最大的数据
Book bookMax = listData.stream()
.max((p1, p2) -> (int) (p1.getPrice() - p2.getPrice()))
.get();
System.out.println(bookMax.getName()+bookMax.getPrice());