之前我们说过为什么要用函数式接口以及函数式接口的好处,本篇文章我们就开始介绍lambda表达式与stream流。
还是要先跟大家说一下函数式接口的特点:
- 函数式接口只有一个抽象方法
- 允许定义静态非抽象方法
- 允许定义默认default非抽象方法
- 允许Java.lang.Object中的public方法
- FunctionInterface注解不是必须的(当我们把该注解定义在接口上方时,如果接口是函数式接口,编译通过;如果不是,编译失败。),因为只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上该注解。
首先我们复习一下什么是lambda表达式
举例:
public void run (String car){
System.out.println("car")
}
我们现在转换成lambda表达式的形式
public void run (String car){
car->System.out.println("car");
}
从上边我们可以看出:箭头左边是参数,箭头右边是方法
转换成流
数组转换成流:
String [] players = Arrays.asList("z","j","x");
Stream.of(players).filter().map();
集合转换成流:
List<String> players=Arrays.asList("z","j","x");
//过滤以x开头,并转换成大写的字符串
players.stream().filter(s->s.startWith("x")).map(String::toUpperCase)
文件转换成流:
Stream<String> stringStream = Files.lines(Paths.get("file.txt"));
谓词:限定条件
例:
List<Employee> employees=Arrays.asList("z","j","x");
List<Employee> employeeList = employees.stream().filter(e->e.getAge()>70 && e.getGender()
.equals("M")).collect(Collertors.toList());
如果现在我们想要封装这个lambda表达式,我们可以用谓词进行封装
public static Predicate<Employee> ageGreaterThan70= x->x.getAge() > 70 ;
public static Predicate<Employee> genderM= x-> x.getGender().equals("M");
现在我们可以用封装好的谓词替换上面的表达式
List<Employee> employeeList = employees.stream()
.filter(
Employee.ageGreaterThan70.and(Employee.genderM))
.collect(Collectors.toList());
Map(peek:不用写返回值)
将一种格式转换成另一种格式,从一种类型转换成另一种类型
List<String> words =Arrays.asList("hello","word");
words.stream().map(s->s.split("")).collect(Collectors.toList()); //split(""):没有分隔符
flatMap
现在如果我们想把集合中的字符串再进行分隔遍历,map已经满足不了我们的需求了,一般我们都会用嵌套for循环来实现,现在我们可以用flatMap代替嵌套for循环
words.stream().flat(s->Arrays.stream(s.split(""))).collect(Collectors.toList());
步骤分解:
s->s.split("")//我们把hello和world转换成stream流.[[h,e,l,l,o],[w,o,r,l,d]]
s->Arrays.stream(s.split(""))//我们将集合再stream一下。
Stream操作过程


排序集合
List<Employee> employees = Arrays.asList(e1,e2,e3,e4);
employees.sort(
Comparator.comparing(Employee::getGender)
.reversed()
.thenComparingInt(Employee::getAge)
.reversed());
//都是正序,不加reversed
//都是倒序,最后面一个加reversed
//先是倒序(加reserved),然后正序
//先是正序(加reserved),然后倒序(加reserved)
::表示方法引用
default关键字
-
解决的问题:当一个接口由很多的实现类的时候,修改这个接口就变成了一个非常麻烦的事,需要修改这个接口的所有实现类
-
default方法可以有自己的默认实现,即有方法体
-
接口实现类可以不去实现default方法,并且可以使用default方法
如何自定义方法再comparator?
匹配规则
anyMatch():判断stream流中是否有符合匹配规则的元素,有返回true,没有返回false
boolean isExistAgeThan70 = false;
for(Employee employee:employees){
if(employee.getAge()>70){
isExistAgeThan70 = true;
break;
}
}
employees.stream().anyMatch(s->s.getAge()>70);
employees.stream().anyMatch(Employee.ageGreaterThan70);
allMatch():判断stream流中是否所有的元素都符合匹配规则的元素,全都符合返回true,有不符合的返回false
noneMatch():判断stream流中是否有符合匹配规则的元素,有返回false,没有返回true
集合元素归约:最后输出一个元素
求和
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6);
//reduce(初始值,归约表达式)
//subtotal:阶段性结果1、3、6、10、15、21
//element:当前值
Integer total = numbers.Stream().reduce(0,(subtotal,element)->subtotal + element);
另一种方法,利用方法引用
Integer total = numbers.Stream().reduce(0,Integer::sum);
字符串操作
List<String> letters=Arrays.asList("a","b","c","d","e");
//第一种方式
String aStr = letters.stream().reduce("",String::concat);
//第二种方式
String aStr = letters.stream().reduce("",(subtotal,element)->subtotal.concat(element));
System.out.println(aStr);
求和员工的年龄
//map将员工对象转换成年龄
Integer tAge = employees.stream().map(Employee::getAge).reduce(0,Integer::sum)
并行流的执行过程

合并器:reduce(初始值,累加器,合并器);当遍历元素和最后累加结果类型不匹配的时候它可以用来对阶段性累加结果进行合并(二次归约、类型转换)
并行操作:
Integer tAge2 = employees.parallelStream().
.map(Employee::getAge)
.reduce(0,Integer::sum,Integer::sum);
Integer tAge3 = employees.stream()
.reduce(0,(subTotal,emp)->subTotal+emp.getAge(),Integer::sum);