JAVA8 Lambda 使用实例

在对Java8 发布的Lambda表达式进行一定了解之后,发现Lambda最核心的就是 结合Stream API对集合数据的遍历、提取、过滤、排序等一系列操作的简化,以一种函数式编程的方式,对集合进行操作。下面总结了几种常用的示例Demo;

Lambda表达式的语法

  基本语法:
  (parameters) -> expression  或  (parameters) ->{ statements; }

含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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)

用lambda表达式实现Runnable

lambda表达式替换了原来匿名内部类的写法,没有了匿名内部类繁杂的代码实现,而是突出了,真正的处理代码。最好的示例就是 实现Runnable 的线程实现方式了: 用() -> {}代码块替代了整个匿名类

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test(){
//old
new Thread((new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类 实现线程");
}
})).start();
//lambda
new Thread( () -> System.out.println("java8 lambda实现线程")).start();
}

forEach 遍历集合

使用 forEach方法,直接通过一行代码即可完成对集合的遍历:

1
2
3
4
5
@Test
public void test1(){
List<Person> list = getPersonList();
list.forEach(person -> System.out.println(person.toString()));
}

执行结果:

1
2
3
4
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)
Person(name=li, age=18, sex=female)
Person(name=wang, age=21, sex=female)

双冒号:: 表示方法引用,可以引用其他方法

1
2
3
4
5
6
7
@Test
public void test2(){
List<Person> list = getPersonList();
Consumer<Person> changeAge = e -> e.setAge(e.getAge() + 3);
list.forEach(changeAge);
list.forEach(System.out::println);
}

执行结果:

1
2
3
4
Person(name=liu, age=25, sex=male)
Person(name=zhao, age=24, sex=male)
Person(name=li, age=21, sex=female)
Person(name=wang, age=24, sex=female)

filter 对集合进行过滤

filter 可以根据传入的 Predicate 对象,对集合进行过滤操作,Predicate 实质就是描述了过滤的条件:

1
2
3
4
5
6
@Test
public void test3(){
List<Person> list = getPersonList();
list.stream().filter(e -> e.getAge() > 20)
.forEach(e -> System.out.println(e.toString()));
}

执行结果:

1
2
3
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)
Person(name=wang, age=21, sex=female)

当需要通过 多个过滤条件对集合进行过滤时,可以采取两种方式:

  1. 可以通过调用多次filter 通过传入不同的 Predicate对象来进行过滤

  2. 也可以通过 Predicate 对象的 and  or 方法,对多个Predicate 对象进行 且 或 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void test4(){
List<Person> list = getPersonList();

Predicate<Person> ageFilter = e -> e.getAge() > 20;
Predicate<Person> sexFilter = e -> e.getSex().equals("male");

//多条件过滤
list.stream().filter(ageFilter)
.filter(sexFilter)
.forEach(e -> System.out.println(e.toString()));
System.out.println("----------------------------");
// Predicate : and or
list.stream().filter(ageFilter.and(sexFilter))
.forEach(e -> System.out.println(e.toString()));
}

执行结果:

1
2
3
4
5
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)
----------------------------
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)

limit 限制结果集的数据量

limit 可以控制 结果集返回的数据条数:返回三条数据,返回年龄>20的前两条数据

1
2
3
4
5
6
7
8
9
@Test
public void test5(){
List<Person> list = getPersonList();
list.stream().limit(3).forEach(e -> System.out.println(e.toString()));

System.out.println("----------------------------");
list.stream().limit(2).filter(e -> e.getAge() > 20)
.forEach(e -> System.out.println(e.toString()));
}

执行结果:

1
2
3
4
5
6
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)
Person(name=li, age=18, sex=female)
----------------------------
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)

sorted 排序

通过sorted,可以按自定义的规则,对数据进行排序,可以用两种写法,分别按 年龄 和 姓名排序

1
2
3
4
5
6
7
8
9
10
11
@Test
public void test6(){
List<Person> list = getPersonList();
//年龄排序
list.stream().sorted((p1,p2) -> (p1.getAge() - p2.getAge()))
.forEach(e -> System.out.println(e.toString()));
//姓名排序
System.out.println("----------------------------");
list.stream().sorted(Comparator.comparing(Person::getName))
.forEach(e -> System.out.println(e.toString()));
}

执行结果:

1
2
3
4
5
6
7
8
9
Person(name=li, age=18, sex=female)
Person(name=zhao, age=21, sex=male)
Person(name=wang, age=21, sex=female)
Person(name=liu, age=22, sex=male)
----------------------------
Person(name=li, age=18, sex=female)
Person(name=liu, age=22, sex=male)
Person(name=wang, age=21, sex=female)
Person(name=zhao, age=21, sex=male)

max min 获取结果中 某个值最大最小的的对象

max min 可以按指定的条件,获取到最大、最小的对象,当集合里有多个满足条件的最大最小值时,只会返回一个对象。

如: 返回年龄最大的人

1
2
3
4
5
6
7
@Test
public void test7(){
List<Person> list = getPersonList();
// 如果 最大最小值 对应的对象有多个 只会返回第一个
Person oldest = list.stream().max(Comparator.comparing(Person::getAge)).get();
System.out.println(oldest.toString());
}

执行结果:

1
Person(name=liu, age=22, sex=male)

map 与 reduce也是两个十分重要的方法

map:对集合中的每个元素进行遍历,并且可以对其进行操作,转化为其他对象,如将集合中的每个人的年龄增加3岁

1
2
3
4
5
6
7
8
9
10
@Test
public void test8(){
List<Person> list = getPersonList();
//将 每人的年龄 +3
System.out.println("修改前:");
list.forEach(e -> System.out.println(e.toString()));
System.out.println("修改后:");
list.stream().map(e -> e.setAge(e.getAge() + 3 ))
.forEach(e -> System.out.println(e.toString()));
}

执行结果:

1
2
3
4
5
6
7
8
9
10
修改前:
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)
Person(name=li, age=18, sex=female)
Person(name=wang, age=21, sex=female)
修改后:
Person(name=liu, age=25, sex=male)
Person(name=zhao, age=24, sex=male)
Person(name=li, age=21, sex=female)
Person(name=wang, age=24, sex=female)

reduce:也是对所有值进行操作,但它是将所有值,按照传入的处理逻辑,将结果处理合并为一个

如:将集合中的所有整数相加,并返回其总和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void test9(){
//第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,
// 这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。
//要注意的是:第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素

//将所有人的年龄加起来 求和
List<Integer> ages = Arrays.asList(2,5,3,4,7);
int totalAge = ages.stream().reduce((sum,age) -> sum + age).get();

System.out.println(totalAge);
//带 初始值的计算, 如果list没有元素 即stream为null 则直接返回初始值
int totalAge1 = ages.stream().reduce(0,(sum,age) -> sum+age);
List<Integer> initList = Lists.newArrayList();
int initTotalAge = initList.stream().reduce(0,(sum,age) -> sum+age);

System.out.println("totalAge1: "+ totalAge1 + " initTotalAge: " + initTotalAge);
}

执行结果:

1
2
21
totalAge1: 21 initTotalAge: 0

collect方法以集合中的元素为基础,生成新的对象

在实际中,我们经常会以集合中的元素为基础,取其中的数据,来生成新的结果集,例如 按照过滤条件,返回新的List,

或者将集合转化为 SetMap等操作,通过collect方法实现是十分简便的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void test10(){
List<Person> list = getPersonList();
//排序过滤等一系列操作之后的元素 放入新的list
List<Person> filterList = list.stream().filter(e -> e.getAge() >20).collect(Collectors.toList());
filterList.forEach(e -> System.out.println(e.toString()));

//将 name 属性用" , ",连接拼接成一个字符串
String nameStr = list.stream().map(Person::getName).collect(Collectors.joining(","));
System.out.println(nameStr);
//将name 放入到新的 set 集合中
Set<String> nameSet = list.stream().map(person -> person.getName()).collect(Collectors.toSet());
nameSet.forEach(e -> System.out.print(e + ","));

System.out.println();
System.out.println("map--------");
Map<String,Person> personMap = list.stream().collect(Collectors.toMap(Person::getName,person -> person));
personMap.forEach((key,val) -> System.out.println(key + ":" + val.toString()));
}

执行结果:

1
2
3
4
5
6
7
8
9
10
Person(name=liu, age=22, sex=male)
Person(name=zhao, age=21, sex=male)
Person(name=wang, age=21, sex=female)
liu,zhao,li,wang
wang,zhao,liu,li,
map--------
wang:Person(name=wang, age=21, sex=female)
zhao:Person(name=zhao, age=21, sex=male)
liu:Person(name=liu, age=22, sex=male)
li:Person(name=li, age=18, sex=female)

summaryStatistics 计算集合元素的最大、最小、平均等值

IntStreamLongStreamDoubleStream 等流的类中,有个非常有用的方法叫做 summaryStatistics(),可以返回 IntSummaryStatisticsLongSummaryStatistics 或者 DoubleSummaryStatistics,描述流中元素的各种摘要数据

1
2
3
4
5
6
7
8
9
10
@Test
public void test11(){
List<Integer> ages = Arrays.asList(2,5,3,4,7);
IntSummaryStatistics statistics = ages.stream().mapToInt(e -> e).summaryStatistics();
System.out.println("最大值: " + statistics.getMax());
System.out.println("最小值: " + statistics.getMin());
System.out.println("平均值: " + statistics.getAverage());
System.out.println("总和: " + statistics.getSum());
System.out.println("个数: " + statistics.getCount());
}

执行结果:

1
2
3
4
5
最大值: 7
最小值: 2
平均值: 4.2
总和: 21
个数: 5