java8的新特性,Lambda表达式和StreamAPI
一、Lambda表达式
是什么:是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
语法规则:Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
参数->执行代码 速记:左右遇一括号省,左侧推断类型省,能省则省
函数式接口:只有一个抽象方法的接口,检查是否为函数式接口@FunctionalInterface
类型推断:Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的 “类型推断”
四大核心函数式接口:
- Comsumer消费型
//有参数无返回值
Consumer c=(a)->System.out.println(a);
- Supplier供给型
//无参数列表,无返回值
Runnable r=()->System.out.println("执行run方法");
- Optional函数型
//两个参数,多条语句,有返回值
Comparator<Integer> com=(a,b)->{
System.out.println("有多条执行语句必须用大括号");
return Integer.compare(a, b);
};
- Predicate断定型
//满足条件的字符串加入集合
public List<String> predicate(List<String> strs,Predicate<String> p){
List<String> strings=new ArrayList<>();
for(String str:strs){
if(p.test(str)){
strings.add(str);
}
}
return strings;
}
@Test
public void test4(){
List<String> ss=Arrays.asList("tom","jack","macho");
List<String> strs=predicate(ss,a->a.length()>3);
System.out.println(strs);
}
方法引用与构造函数引用
方法引用
- 类名::方法名
@Test
public void test3(){
/*BiPredicate<String, String> bp=(x,y)->x.equals(y);
boolean b=bp.test("tom", "jack");
System.out.println(b);*/
BiPredicate<String, String> bp=String::equals;
boolean b=bp.test("tom", "jack");
System.out.println(b);
}
- 对象名::方法名
emps.stream().map(Employee::getName).forEach(System.out::println);
- 类::静态方法名
构造器引用
对象引用
//构造器引用
@Test
public void test4(){
/*Supplier<Employee> s=()->new Employee();
Employee emp=s.get();*/
Supplier<Employee> s=Employee::new;
Employee emp=s.get();
System.out.println(emp);
}
数组引用
//数组引用
@Test
public void test5(){
/*Function<Integer, String[]> f=x->new String[x];
String[] s=f.apply(20);
System.out.println(s.length);*/
Function<Integer, String[]> f=String[]::new;
String[] s=f.apply(20);
System.out.println(s.length);
}
二、 StramAPI
是什么:处理集合类似使用sql执行数据库查询
使用步骤:
- 创建Stream流
- 中间操作
- 终止操作
步骤一:创建Stream流
方法一:Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
- Stream stream() : 返回一个顺序流
- Stream parallelStream() : 返回一个并行流
List<String> list=new ArrayList<>();
Stream<String> listStream=list.stream();
方法二:由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static Stream stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
Employee[] emps=new Employee[10];
Stream<Employee> eSteam=Arrays.stream(emps);
方法三:由值创建流
可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static Stream of(T… values) : 返回一个流。
Stream<String> staticStream=Stream.of("hello","tom","jack");
方法四:由函数创建流,创建无限流
可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。
Stream<Integer> s=Stream.iterate(0, x->x+2);
s.limit(10).forEach(System.out::println);
Stream<Double> generate=Stream.generate(()->Math.random()*100);
generate.limit(10).forEach(System.out::println);
步骤二:中间操作
- 筛选,切片,去重
@Test
public void test(){
emps.stream().filter(e->{
System.out.println("执行中间操作");
return e.getAge()>30;
//终止操作时才能够执行全部内容,惰性求值
}).forEach(System.out::println);
}
@Test
public void test2(){
emps.stream().filter(e->{
System.out.println("短路");
return e.getAge()>20;
})
.limit(2)
.forEach(System.out::println);
}
@Test
public void test3(){
emps.stream().filter(e->e.getAge()>20)
.skip(3)
.forEach(System.out::println);
}
- 映射
/**
* map映射
*/
@Test
public void test5(){
emps.stream().map(Employee::getName).forEach(System.out::println);
System.out.println("--------------");
emps.stream().map(e->e.getName().toUpperCase()).forEach(System.out::println);
}
- 排序:默认是自然排序
/**
* 排序
*/
@Test
public void test7(){
emps.stream().sorted((e1,e2)->{
if(e1.getAge().equals(e2)){
return e1.getSal().compareTo(e2.getSal());
}else{
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
步骤三:终止操作
规约
可以将流中元素反复结合起来,得到一个值。返回 T
//规约reduce,计算和
List<Integer> num=Arrays.asList(1,2,4,5);
Integer sum=num.stream().reduce(0,(x,y)->x+y);
System.out.println(sum);
//计算工资总和
Optional<Integer> totalSal=emps.stream().map(e->e.getSal()).reduce((x,y)->Integer.sum(x, y));
Optional<Integer> totalSal2=emps.stream().map(Employee::getSal).reduce(Integer::sum);
收集
将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法。Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例。
/**
* collect汇总总数,平均,总和,最大,最小Collectors.
*/
@Test
public void test3(){
Long count=emps.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("=================");
Double average=emps.stream().collect(Collectors.averagingLong(Employee::getSal));
System.out.println(average);
System.out.println("=================");
Long sum=emps.stream().collect(Collectors.summingLong(Employee::getSal));
System.out.println(sum);
Optional<Integer> max=emps.stream().map(Employee::getSal).collect(Collectors.maxBy(Integer::compare));
System.out.println(max.get());
System.out.println("=================");
Optional<Employee> min=emps.stream().collect(Collectors.minBy((x,y)->Integer.compare(x.getSal(), y.getSal())));
System.out.println(min.get().getSal());
}
/**
* 分组
*/
@Test
public void test4(){
//按工作状态分组
Map<Status,List<Employee>> group=emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(group);
}
/**
* 多级分组
*/
@Test
public void test5(){
Map<Status,Map<String,List<Employee>>> groups=emps.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy(e->{
if(((Employee)e).getAge()<25){
return "青年";
}else if(((Employee)e).getAge()>=25&&((Employee)e).getAge()<45){
return "中年";
}else{
return "老年";
}
})));
System.out.println(groups);
}
/**
* 分区
*/
@Test
public void test6(){
Map<Boolean,List<Employee>> trueorfalse=emps.stream().collect(Collectors.partitioningBy(e->e.getSal()>5000));
System.out.println(trueorfalse);
}