lambda与stream是java8中比较重要两个新特性,lambda表达式采用一种简洁的语法定义代码块,允许我们将行为传递到函数中。之前我们想将行为传递到函数中,仅有的选择是使用匿名内部类,现在我们可以使用lambda表达式替代匿名内部类。在学习lambda表达式之前,建议各位看官先去学习一下匿名内部类(JAVA基础知识|内部类)。
stream提供了很多有用的api,方便了我们对集合的操作
一、lambda表达式
基本语法:
(parameters) -> expression
或
(parameters) ->{ statements; }
lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
以下是一些简单的例子,便于我们理解这些特性:
// 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表达式使用
2.1、在for循环中使用
package com.my.controller;import junit.framework.TestCase; import org.junit.Test;import java.util.ArrayList; import java.util.List;/*** description:{description}* author:jyy* date:2018-01-09 16:43* modify:{modify}*/ public class AppTest extends TestCase {@Testpublic void test() {List<String> list = new ArrayList<>();list.add("北京");list.add("上海");list.add("广州");list.add("深圳");for (String str : list) {System.out.println(str);}System.out.println("=================");list.forEach(str -> System.out.println(str));}}
执行结果:
北京 上海 广州 深圳 ================= 北京 上海 广州 深圳
2.2、替代匿名内部类使用
我们使用JAVA基础知识|内部类中的try catch示例
package com.my.controller;import junit.framework.TestCase; import org.junit.Test;import java.util.ArrayList; import java.util.List;/*** description:{description}* author:jyy* date:2018-01-09 16:43* modify:{modify}*/ public class AppTest extends TestCase {@Testpublic void test() {//匿名内部类new ExceptionTemplate().execute(new CatchExceptionable() {@Overridepublic void catchException() {System.out.println("代码");}});//lambda表达式new ExceptionTemplate().execute(() -> System.out.println("代码"));}}
2.3、lambda表达式与Comparator类结合使用
package com.my.controller;import junit.framework.TestCase; import org.junit.Test;import java.util.ArrayList; import java.util.Comparator; import java.util.List;/*** description:{description}* author:jyy* date:2018-01-09 16:43* modify:{modify}*/ public class AppTest extends TestCase {@Testpublic void test() {List<String> list = new ArrayList<>();list.add("BeiJing");list.add("ShangHai");list.add("GuangZhou");list.add("ShenZhen");list.sort(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}});list.forEach(str -> System.out.println(str));System.out.println("==============");List<String> list2 = new ArrayList<>();list2.add("BeiJing");list2.add("ShangHai");list2.add("GuangZhou");list2.add("ShenZhen");//list2.sort((String o1,String o2) -> o1.compareTo(o2));Comparator<String> comparator =(String o1,String o2) -> o1.compareTo(o2);list2.sort(comparator);list2.forEach(str -> System.out.println(str));} }
执行结果:
BeiJing GuangZhou ShangHai ShenZhen ============== BeiJing GuangZhou ShangHai ShenZhen
三、流stream
Java 8 中的stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。stream API 借助于同样新出现的 lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势
生成流的两种方式:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
下面我们就来使用stream提供的各种API:
3.1、筛选和切片
方法 | 描述 |
filter | 从流中过滤元素 |
distinct | 通过流所生成的元素的hashCode()和equals()方法去重 |
limit | 截断流,选取前n个元素 |
skip | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足n个,则返回一个空流 |
package com.my.po;/*** description:{description}* author:jyy* date:2018-02-11 11:06* modify:{modify}*/ public class Employee {private String id;private String name;private double salary;private String sex;public Employee(String id, String name, double salary,String sex) {this.id = id;this.name = name;this.salary = salary;this.sex=sex;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "Employee{" +"id='" + id + '\'' +", name='" + name + '\'' +", salary=" + salary +", sex='" + sex + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Employee employee = (Employee) o;return id.equals(employee.id);}@Overridepublic int hashCode() {return id.hashCode();} }
package com.my.controller;import com.my.po.Employee; import junit.framework.TestCase; import org.junit.Test;import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects;/*** description:{description}* author:jyy* date:2018-01-09 16:43* modify:{modify}*/ public class AppTest extends TestCase {@Testpublic void test() {Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1004", "谢楠", 11000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);//forEach,查询所有数据list.stream().forEach(e -> System.out.println(e.toString()));//filter,查询集合中所有的女性list.stream().filter(e -> Objects.equals(e.getSex(), "female")).forEach(e -> System.out.println(e.toString()));//查询集合中薪资大于6000的雇员list.stream().filter(e -> e.getSalary() > 7000).forEach(e -> System.out.println(e));//limit,查询前两条数据list.stream().limit(2).forEach(e -> System.out.println(e.toString()));//distinct,去重,利用Employee对象中的hashCode()和equals()方法list.stream().distinct().forEach(e -> System.out.println(e));//skip,跳过前两个list.stream().skip(2).forEach(e -> System.out.println(e));} }
3.2、映射
方法 | 描述 |
map(Function f) | 接受一个函数作为参数,并将函数应用到每一个元素上,返回新的元素 |
mapToDouble(ToDoubleFunction f) | 返回的新元素为double类型 |
mapToInt(ToIntFunction f) | 返回的新元素为int类型 |
mapToLong(ToLongFunction f) | 返回的新元素为long类型 |
flatMap(Function f) | 操作多层嵌套的流,使其扁平化 |
3.2.1、map
Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1004", "谢楠", 11000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);//maplist.stream().map(e -> e.getSalary()).forEach(e -> System.out.println(e));
执行结果:
5000.0 7000.0 10000.0 11000.0 11000.0
可以看出,集合list经过map操作之后,类型已经改变。具体什么类型,由返回值决定
3.2.2、mapToDouble、mapToInt、mapToLong
Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1004", "谢楠", 11000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);list.stream().mapToDouble(e -> e.getSalary()).forEach(e -> System.out.println(e));
执行结果:
5000.0 7000.0 10000.0 11000.0 11000.0
3.2.3、flatMap
Employee[] employees1 = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1004", "谢楠", 11000, "female")};Employee[] employees2 = {new Employee("1005", "Marry", 5000, "male"),new Employee("1006", "Linda", 7000, "male"),new Employee("1007", "Cris", 10000, "female")};List<Employee[]> list = new ArrayList<>();list.add(employees1);list.add(employees2);list.stream().flatMap(e -> Arrays.stream(e)).forEach(e -> System.out.println(e.toString()));
执行结果:
Employee{id='1001', name='李明', salary=5000.0, sex='male'} Employee{id='1002', name='王明', salary=7000.0, sex='male'} Employee{id='1003', name='张丽', salary=10000.0, sex='female'} Employee{id='1004', name='谢楠', salary=11000.0, sex='female'} Employee{id='1005', name='Marry', salary=5000.0, sex='male'} Employee{id='1006', name='Linda', salary=7000.0, sex='male'} Employee{id='1007', name='Cris', salary=10000.0, sex='female'}
3.3、排序
方法 | 描述 |
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1005", "Marry", 6000, "male"),new Employee("1006", "Linda", 9000, "male"),new Employee("1007", "Cris", 10000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);list.stream().map(e -> e.getSalary()).sorted().forEach(e -> System.out.println(e.toString()));System.out.println("=======");Comparator<String> comparator = (String o1, String o2) -> o1.compareTo(o2);list.stream().map(e -> e.getId()).sorted(comparator).forEach(e -> System.out.println(e.toString()));
执行结果:
5000.0 6000.0 7000.0 9000.0 10000.0 10000.0 11000.0 ======= 1001 1002 1003 1004 1005 1006 1007
3.4、查找与匹配
方法 | 描述 |
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了) |
Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1005", "Marry", 6000, "male"),new Employee("1006", "Linda", 9000, "male"),new Employee("1007", "Cris", 10000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);System.out.println("===allMatch===");Boolean b1 = list.stream().allMatch(e -> e.getSalary() > 4000);Boolean b2 = list.stream().allMatch(e -> e.getSalary() > 5000);System.out.println(b1);System.out.println(b2);System.out.println("===anyMatch===");Boolean b3 = list.stream().anyMatch(e -> e.getSalary() > 10000);Boolean b4 = list.stream().anyMatch(e -> e.getSalary() > 11000);System.out.println(b3);System.out.println(b4);System.out.println("===noneMatch===");Boolean b5 = list.stream().noneMatch(e -> e.getSalary() > 10000);Boolean b6 = list.stream().noneMatch(e -> e.getSalary() > 11000);System.out.println(b5);System.out.println(b6);System.out.println("===findFirst===");System.out.println(list.stream().findFirst().toString());System.out.println("===findAny===");System.out.println(list.stream().findAny().toString());System.out.println("===count===");System.out.println(list.stream().count());System.out.println("===max===");System.out.println(list.stream().max((Employee o1, Employee o2) -> {if (o1.getSalary() > o2.getSalary()) return 1;else return -1;}).toString());System.out.println("===min===");System.out.println(list.stream().min((Employee o1, Employee o2) -> {if (o1.getSalary() > o2.getSalary()) return 1;else return -1;}).toString());
执行结果:
===allMatch=== true false ===anyMatch=== true false ===noneMatch=== false true ===findFirst=== Optional[Employee{id='1001', name='李明', salary=5000.0, sex='male'}] ===findAny=== Optional[Employee{id='1001', name='李明', salary=5000.0, sex='male'}] ===count=== 7 ===max=== Optional[Employee{id='1004', name='谢楠', salary=11000.0, sex='female'}] ===min=== Optional[Employee{id='1001', name='李明', salary=5000.0, sex='male'}]
3.5、归约
map-reduce模式,在mongoDB、spark、hadoop等都有它的身影,因google使用它进行网络搜索而出名
方法 | 描述 |
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional<T> |
Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1005", "Marry", 6000, "male"),new Employee("1006", "Linda", 9000, "male"),new Employee("1007", "Cris", 10000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);String result1 = list.stream().map(e -> e.getName()).reduce("", (x, y) -> x + "," + y);System.out.println(result1.substring(1));Optional<String> result2 = list.stream().map(e -> e.getName()).reduce((x, y) -> x + "," + y);System.out.println(result2.get());
执行结果:
李明,王明,张丽,Marry,Linda,Cris,谢楠
李明,王明,张丽,Marry,Linda,Cris,谢楠
3.6、收集
方法 | 描述 |
collect(Collector c) | 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Employee[] employees = {new Employee("1001", "李明", 5000, "male"),new Employee("1002", "王明", 7000, "male"),new Employee("1003", "张丽", 10000, "female"),new Employee("1005", "Marry", 6000, "male"),new Employee("1006", "Linda", 9000, "male"),new Employee("1007", "Cris", 10000, "female"),new Employee("1004", "谢楠", 11000, "female")};List<Employee> list = Arrays.asList(employees);List<String> collect = list.stream().map(e -> e.getName()).collect(Collectors.toList());collect.forEach(System.out::println);System.out.println("-------------------");Set<String> set = list.stream().map(e -> e.getName()).collect(Collectors.toSet());set.forEach(System.out::println);System.out.println("-------------------");HashSet<String> hashSet = list.stream().map(e -> e.getName()).collect(Collectors.toCollection(HashSet::new));hashSet.forEach(System.out::println);System.out.println("-------------------");//分组Map<Double, List<Employee>> group = list.stream().collect(Collectors.groupingBy(e -> e.getSalary()));System.out.println(group);
执行结果:
李明 王明 张丽 Marry Linda Cris 谢楠 ------------------- 张丽 Cris 李明 王明 Linda Marry 谢楠 ------------------- 张丽 Cris 李明 王明 Linda Marry 谢楠 {9000.0=[Employee{id='1006', name='Linda', salary=9000.0, sex='male'}], 10000.0=[Employee{id='1003', name='张丽', salary=10000.0, sex='female'}, Employee{id='1007', name='Cris', salary=10000.0, sex='female'}], 5000.0=[Employee{id='1001', name='李明', salary=5000.0, sex='male'}], 11000.0=[Employee{id='1004', name='谢楠', salary=11000.0, sex='female'}], 6000.0=[Employee{id='1005', name='Marry', salary=6000.0, sex='male'}], 7000.0=[Employee{id='1002', name='王明', salary=7000.0, sex='male'}]}
以上内容只是对lambda表达式和stream的简单介绍,在实际使用中要复杂的多