JDK1.8新特性-Lambda表达式,方法引用,Stream API的使用
Lambda表达式
Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。下面这个例子就是使用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)
使用场景(举例):
1.集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
//遍历
numbers.forEach(x -> System.out.println(x));
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "大数据", "高薪!");
// 按照条件进行删除
list.removeIf(ele -> ele.endsWith(".m"));
// 批量替换
list.replaceAll(ele -> ele.concat("!"));
// 自定义排序
list.sort((e1, e2) -> e2.compareTo(e1));
// 遍历 (这里用了方法引用下面会解释)
list.forEach(System.out::println);
2.多线程
Thread thread = new Thread(() -> {
// 线程中的处理
});
方法引用
在学习lambda表达式之后,我们通常使用lambda表达式来创建匿名方法。然而,有时候我们仅仅是调用了一个已存在的方法。 在Java8中,我们可以直接通过方法引用来简写lambda表达式中已经存在的方法。
这种特性就叫做方法引用(Method Reference)。
使用语法
使用场景
一.普通引用
- 对象::实例方法名
@Test
public void test1(){
//原来实现
PrintStream ps=System.out;
Consumer<String> con=(x)->ps.println(x);
con.accept("厚溥百里半");
//使用方法引用
Consumer<String>con2=ps::println;
con2.accept("用心做教育");
}
@Test
public void test2(){
//原来实现
Emp emp = new Emp("java1130班");
Supplier<String>sup=()->emp.getName();
System.out.println(sup.get());
//使用方法引用
Emp emp2 = new Emp("天下无敌");
Supplier<String>sup2=emp2::getName;
System.out.println(sup2.get());
}
2.类::静态方法名
@Test
public void test3(){
//原来的实现
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
System.out.println(com.compare(100, 99));
//使用方法的引用
Comparator<Integer> com2=Integer::compareTo;
System.out.println(com2.compare(100, 99));
}
3.类::实例方法名
@Test
public void test4(){
//原来的实现
BiPredicate<String,String> bp=(x,y)->x.equals(y);
//使用方法的引用
BiPredicate<String,String> bp2=String::equals;
}
注意:
- 方法引用简化有参方法时, Lambda体中调用方法的参数列表与返回值类型,要和函数式接口中抽象方法的参数列表和返回值类型保持一致!
- 若Lambda参数列表中的第一参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName::method (Arrays.sort(strArr, String::compareToIgnoreCase);)
二.构造方法引用
1.示例代码
@Test//无参构造
public void test5(){
//原来的实现
Supplier<Emp> sup=()->new Emp();
Emp emp = sup.get();
//构造器引用
Supplier<Emp> sup2=Emp::new;
Emp emp1 = sup2.get();
}
@Test//有参构造
public void test6(){
//原来的实现
Function<String,Emp> fun=(x)->new Emp(x);
Emp emp = fun.apply("厚溥");
//构造器引用
Function<String,Emp> fun2=Emp::new;
Emp emp2 = fun2.apply("厚溥");
}
注意:
- 需要调用的构造器参数列表要与函数式接口中抽象方法的参数列表保持一致!
三.数组引用
1.示例代码
@Test
public void test7(){
//原来的实现
Function<Integer,String[]> fun=(x)->new String[x];
String[] arrs = fun.apply(10);
//构造器引用
Function<Integer,String[]> fun2=String[]::new;
String[] arrs2 = fun2.apply(20);
}
案例:
- 遍历集合中的元素并输出
List<String> list = Arrays.asList("bb", "aa", "ee", "dd", "cc");
//lambda表达式实现
list.forEach(e-> System.out.println(e));
//方法引用实现 类名::静态方法名
list.forEach(System.out::println);
- 对一个字符串数组进行排序
String [] strArr={"bb", "AA", "ee", "DD", "cc"};
//lambda表达式实现排序
Arrays.sort(strArr,(s1,s2)->s1.compareToIgnoreCase(s2));
//方法引用实现排序 类名::方法名
Arrays.sort(strArr, String::compareToIgnoreCase);
//Arrays工具类 打印出数组
System.out.println(Arrays.toString(strArr));
Stream API
1.理解流
流到底是什么呢?
是数据渠道,用于操作数据源(集合,数组)所生成的元素序列。集合讲的是数据,流讲的是计算!
注意:
1.Stream自己不会存储数据
2.Stream不会改变源对象,相反,它们会返回一个持有结果的新的Stream
3.Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。
2.使用流
(1).创建Stream
通过一个数据源(数组或集合),获取一个流。
@Test//创建Stream
public void test1(){
//1.通过Collection系列集合提供的stream()
ArrayList<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2.通过Arrays 中的静态方法stream() 获取数组流
IntStream stream2 = Arrays.stream(new int[5]);
DoubleStream stream2_1 = Arrays.stream(new double[5]);
Stream<String> stream2_2 = Arrays.stream(new String[5]);
//3.通过Stream类的静态方法of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
//4.创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(()->Math.random()).limit(6).forEach(System.out::println);
}
(2).中间操作
一个中间操作链,对数据源的数据进行处理。
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,这个称为“惰性求值”。
(3).终止操作
一个终止操作,执行中间操作链,并产生结果
package stream;
public class TestStream2 {
List<Emp> emps=Arrays.asList(
new Emp("曹操",18,99.99),
new Emp("刘备",56,555.55),
new Emp("张飞",34,888.88),
new Emp("孙权",25,666.66),
new Emp("吕布",12,111.11),
new Emp("吕布",12,111.11),
new Emp("吕布",12,111.11)
);
/*
筛选与切片:
filter 从流中排除某些元素
limit 使其元素不超过给定数量
skip 跳过元素,返回一个扔掉了前n个元素的流
distinct 通过流所生成元素的hashCode()和equals()去重
*/
@Test
public void test1(){
//中间操作
Stream<Emp> steam = emps.stream().filter((e) -> {
System.out.println("Steam 的中间操作 ");
return e.getAge() > 35;
});
//终止操作
steam.forEach(System.out::println);
}
@Test
public void test2(){
//求工资大于300的前2名
emps.stream().filter((e) -> e.getSalary() > 300)
.limit(2).forEach(System.out::println);
}
@Test
public void test3(){
//求工资大于300的员工-跳过前2名
emps.stream().filter((e) -> e.getSalary() > 300)
.skip(2).forEach(System.out::println);
}
@Test
public void test4(){
//员工信息去重
emps.stream().distinct().forEach(System.out::println);
}
/*
映射:
map-接收Lambda,将元素转换成其它形式或提取信息。接收一个函数作为参数,
该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap --接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
*/
@Test
public void test5(){
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
list.stream()
.map(s->s.toUpperCase())
.forEach(System.out::println);
System.out.println("-------------------------");
emps.stream()
.map(Emp::getName)
.forEach(System.out::println);
}
@Test//排序
public void test2(){
//自然排序
List<String> list = Arrays.asList("cc", "ee", "dd", "ff", "aa", "bb");
list.stream().sorted().forEach(System.out::println);
//外部比较器排序
emps.stream().sorted((e1,e2)->{
if(e1.getAge()==e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else {
return e1.getAge()-e2.getAge();
}
}).forEach(System.out::println);
}
/*
* 查找与匹配
* allMatch 检查是否匹配所有元素
* anyMatch 检查是否至少匹配一个元素
* noneMatch 检查是否没有匹配所有元素
* findFirst 返回第一个元素
* findAny 返回当前流中任意元素
* */
@Test
public void test3(){
boolean b = emps.stream().allMatch(e -> e.getStatus().equals(Emp.Status.BUSY));
System.out.println(b);
boolean b2 = emps.stream().anyMatch(e -> e.getStatus().equals(Emp.Status.BUSY));
System.out.println(b2);
boolean b3 = emps.stream().noneMatch(e -> e.getStatus().equals(Emp.Status.BUSY));
System.out.println(b3);
Optional<Emp> op = emps.stream().sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).findFirst();
System.out.println(op.get());
Optional<Emp> op2 = emps.parallelStream().filter(e -> e.getStatus().equals(Emp.Status.BUSY)).findAny();
System.out.println(op2.get());
}
@Test//count和 max ,min
public void test4(){
System.out.println(emps.stream().count());
Optional<Emp> op = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op.get());
Optional<Double> op2 = emps.stream().map(Emp::getSalary).min(Double::compareTo);
System.out.println(op2.get());
}
}