首先新建一个测试Bean
package com.lambda.bean;
public class Employee {
private String name;
private Integer age;
private float price;
private Status status;
public Employee(){
}
public Employee(String name, Integer age, float price) {
this.name = name;
this.age = age;
this.price = price;
}
public Employee(String name, Integer age, float price, Status status) {
this.name = name;
this.age = age;
this.price = price;
this.status = status;
}
public Employee(float price){
this.price=price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public float getPrice() {
return price;
}
public float getPrice1(float price){
return price;
}
public void setPrice(float price) {
this.price = price;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", price=" + price +
", status=" + status +
'}';
}
public enum Status{
FREE,
BUSY,
VICATION;
}
}
//新建测试 demo 类
public class Demo1 {
List<Employee> employees = Arrays.asList(
new Employee("张三",22,8888.88f, Employee.Status.BUSY),
new Employee("李四",42,4444.44f, Employee.Status.BUSY),
new Employee("王五",32,6666.66f, Employee.Status.FREE),
new Employee("赵六",52,7777.77f, Employee.Status.FREE),
new Employee("田七",62,3333.33f, Employee.Status.BUSY),
new Employee("王八",12,9999.99f, Employee.Status.VICATION)
);
/**
* Lambda 表达式基础语法
*/
@Test
public void test1() {
// 对比之前
Runnable runnable = new Runnable(){
@Override
public void run() {
System.out.println("hello world!");
}
};
runnable.run();
// Lambda
// 语法格式一:无参,无返回值
Runnable r = () -> System.out.println("Hello Lambda!");
r.run();
// 语法格式二:有参,无返回值
Consumer<String> consumer = (e) -> System.out.println(e);
consumer.accept("Hello Lambda Consumer!");
//语法格式三:有一个参数,小括号可以不写
Consumer<String> c = e -> System.out.println(e);
c.accept("Hello Lambda Consumer!");
//语法格式四:有两个以上的参数,Lambda 体中有多条语句
Comparator<Integer> comparator = (x, y) -> {
System.out.println("排序开始");
return Integer.compare(x, y);
};
//语法格式五:若 Lambda 体中只有一条语句, return 和大括号都可以省略不写
Comparator<Integer> comparator1 = (Integer x, Integer y) -> Integer.compare(x, y);
//语法格式六:Lambda 参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
Comparator<Integer> comparator2 = (x, y) -> Integer.compare(x, y);
}
/**
* 四大核心函数式接口
* Consumer<T>:消费型接口
* void accept(T t);
*
* Supplier<T>:供给行接口
* T get();
*
* Function<T,R> : 函数型接口
* R apply(T t);
*
* Predicate<T> : 断言型接口
* R apply(T t);
*/
@Test
public void test2(){
// Consumer<T>:消费型接口
Consumer<String> consumer= (e)-> System.out.println("Hello "+e);
consumer.accept("world!");
// Supplier<T>:供给行接口
Supplier<String> supplier = ()->"Hello";
System.out.println(supplier.get());
//Function<T,R> : 函数型接口
Function<Integer,Integer> function = (e)->e*10;
Integer sum = function.apply(10);
System.out.println(sum);
//Predicate<T> : 断言型接口
Predicate<String> predicate = e->e.equals("hello world");
System.out.println(predicate.test("hello"));
System.out.println(predicate.test("hello world"));
}
/**
方法引用:若 Lambda 体中的内容有方法已经实现,我们可以使用“方法引用”
(可以理解为方法引用是 Lambda 表达式的另外以中表现形式)
主要有三种语法格式:
对象::实列方法名
类::静态方法名
类::实列方法名
注意:
1. Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的韩术列表和返回值保持一致!
2. 若 Lambda 参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以用 ClassName::method
数组引用:Type[]::new
*/
@Test
public void test3(){
//对象::实列方法名
Consumer<String> consumer = System.out::println;
consumer.accept("Hello world");
Employee employee= new Employee();
employee.setAge(10);
Supplier<Integer> supplier=employee::getAge;
System.out.println(supplier.get());
Employee employee1= new Employee();
Function<Float,Float> function=employee1::getPrice1;
System.out.println(function.apply(10f));
//类::静态方法名
Comparator<Integer> comparator= Integer::compare;
System.out.println(comparator.compare(10,1));
//类::实列方法名
BiPredicate<String,String> biPredicate = String::equals;
System.out.println(biPredicate.test("a","a"));
//构造器引用
Supplier<Employee> supplier1= Employee::new;
System.out.println(supplier1.get());
Function<Float,Employee> function1=Employee::new;
System.out.println(function1.apply(11f));
//数组引用:Type[]::new
Function<Integer,String[]> f = (e)->new String[e];
System.out.println(f.apply(10).length);
Function<Integer,String[]> f1=String[]::new;
System.out.println(f1.apply(20).length);
}
/**
* 查找与匹配
* allMatch--检查是否匹配所有元素
* anyMath--检查是否至少匹配一个元素
* noneMatch--检查是否没有匹配所有元素
* findFirst--返回第一个元素
* findAny-- 返回当前流中的任意元素
* count--返回流中元素的总个数
* max--返回流中最大值
* min--返回流中最小值
*/
@Test
public void test4(){
boolean b = employees.stream().allMatch((e)->e.getPrice()>3000);
System.out.println(b);
boolean b1 = employees.stream().anyMatch((e)->e.getPrice()>5000);
System.out.println(b1);
boolean b2 = employees.stream().noneMatch((e)->e.getPrice()>10000);
System.out.println(b2);
Optional<Employee> opt = employees.stream().findFirst();
System.out.println(opt);
Optional<Employee> opt1 = employees.stream().findAny();
System.out.println(opt1);
Long count = employees.stream().count();
System.out.println(count);
Optional<Employee> opt3 = employees.stream().max((e1,e2)->Float.compare(e1.getPrice(),e2.getPrice()));
System.out.println(opt3.get());
Optional<Float> opt4 = employees.stream().map(Employee::getPrice).min(Float::compareTo);
System.out.println(opt4.get());
}
/**
* 规约与收集
*
* 规约-- 可以将流中元素结合起来得到一个值。
* reduce(T identity,BinaryOerator)
* reduce(BinaryOperator)
*
* 收集--collect 接收一个 Collector 接口的实现,用于给 Stream 元素汇总的方法
*/
@Test
public void test5(){
// 规约--reduce
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0,(x,y)->x+y);
System.out.println(sum);
//统计员工工资总和
Optional<Float> opt = employees.stream().map(Employee::getPrice).reduce(Float::sum);
System.out.println(opt.get());
//收集--collect
employees.stream().map(Employee::getPrice).collect(Collectors.toList()).forEach(System.out::println);
//平均值
Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getPrice));
System.out.println(avg);
//总合
Double sum1 = employees.stream().collect(Collectors.summingDouble(Employee::getPrice));
System.out.println(sum1);
//最大值
Optional opt1 = employees.stream().collect(Collectors.maxBy((e1,e2)->Float.compare(e1.getPrice(),e2.getPrice())));
System.out.println(opt1.get());
//最小值
Optional opt2 = employees.stream().map(Employee::getPrice).collect(Collectors.minBy(Float::compare));
System.out.println(opt2.get());
//分组
Map<Employee.Status,List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
//多级分组
Map<Employee.Status,Map<String,List<Employee>>> map1 = employees.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e)->{
if(e.getAge()>20){
return "青年";
}else if(e.getAge()>30){
return "中年";
}else{
return "老年";
}
})));
System.out.println(map1);
//分区
Map<Boolean,List<Employee>> map3 = employees.stream().collect(Collectors.partitioningBy(e->e.getAge()>30));
System.out.println(map3);
//Summary 使用
IntSummaryStatistics summary = employees.stream().collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(summary.getMax());
System.out.println(summary.getAverage());
System.out.println(summary.getCount());
// join 拼接
String str = employees.stream().map(Employee::getName).collect(Collectors.joining());
System.out.println(str);
}
/**
* 并行流-parallel
*/
// 20亿 888 毫秒左右
@Test
public void test6(){
Instant start = Instant.now();
Long sum = LongStream.rangeClosed(0L,2000000000L).parallel().reduce(0,Long::sum);
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis());
}
// 对比串行流 20亿 1387 毫秒左右。在往上加到 50 亿,串行流我这里已经跑不动了,但是并行parallel的可以
@Test
public void test7(){
Instant start = Instant.now();
long sum = 0L;
for(int i=0;i<=2000000000L;i++){
sum +=i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis());
}
}
文档说明:
一,Lambda 表达式基础语法:Java8中引入了一个新的操作符 "->" 改操作符称为箭头操作符或 Lambda 操作符
箭头操作符将 Lambda 表达式擦划分成两部分:
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式所需要执行的功能,即 Lambda 体
语法格式一:无参,无返回值
() -> System,out.printLn("Hello Lambda!");
语法格式二:有一个参数,无返回值
(e) -> System.out.println(e);
语法格式三:有一个参数,小括号可以不写
e -> System.out.println(e);
语法格式四:有两个以上的参数,Lambda 体中有多条语句
Comparator<Integer> comparator = (x,y)->{
System.out.println("排序开始");
return Integer.compare(x,y);
};
语法格式五:若 Lambda 体中只有一条语句, return 和大括号都可以省略不写
Comparator<Integer> comparator1 = (x,y)-> Integer.compare(x,y);
语法格式六:Lambda 参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
(Integer x,Integer y)-> Integer.compare(x,y);
二,Lambda 表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用 @FunctionalInterface 修饰
可以检查是否是函数式接口
java8 中四大核心函数式接口:
Consumer<T>:消费型接口
void accept(T t);
Superlier<T>:供给行接口
T get();
Function<T,R> : 函数型接口
R apply(T t);
Predicate<T> : 断言型接口
R apply(T t);
三,方法引用:若 Lambda 体中的内容有方法已经实现,我们可以使用“方法引用”(可以理解为方法引用是 Lambda 表达式的另外以中表现形式)
主要有三种语法格式:
对象::实列方法名
Consumer<String> consumer = System.out::println;
类::静态方法名
Comparator<Integer> comparator= Integer::compare;
类::实列方法名
BiPredicate<String,String> biPredicate = String::equals;
注意: 1. Lambda 体重条用方法的参数列表与返回值类型,要与函数式接口中抽象方法的韩术列表和返回值保持一致!
2. 若 Lambda 参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以用 ClassName::method
数组引用:Type[]::new
Function<Integer,String[]> f1=String[]::new;
四 Stream
一,Stream 的三个操作步骤:
1. 创建 Stream
集合方式:list.stream()
数组方式:arrays.stream()
arrays 静态方法:arrays.steam(arrays)
Stream 静态方法 of:Stream.of("aa","bb","cc")
无限流,迭代:Stream.iterate(0,(x)->x+2)
多个中间操作可以链接起来形成一个流水线,
除非流水线上触发终止操作,否则中间操作不会执行任何的处理!
而在终止操作时一次性全部处理,称为“惰性求值”。
2. 中间操作
list.stream().short,limt(),filter......
3. 终止操作
stream.forEach(System.out::println);
二,中间操作
映射
map:将元素转换成其他形式或提取信息。 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream().map((str)->str.toUpperCase()).forEeach(System.out::println);
map 返回格式:{{a,a},{b,b},{c,c},{d,d}}
flatMap:接收一个函数 作为参数,将流中的每个值链接成一个流
list.stream().flatMap((str)->str.toUpperCase());
flatMap 返回格式:{a,a,b,b,c,c,d,d}
排序
shorted()--自然排序
List<String> list = Arrays.asList("bb","aa","cc","dd");
list.stream().shorted().forEache(System.out::println);
shorted(Comparator com)--定制排序
List<Employee> employees = Arrays.asList(
new Employee("张三",22,8888.88f),
new Employee("李四",42,4444.44f),
new Employee("王五",32,6666.66f),
new Employee("赵六",52,7777.77f),
);
employees.stream()
.shorted(e1,e2) ->e1.getAge().compareTo(e2.getAge())
.forEache(System.out::println);
三,查找与匹配
allMatch--检查是否匹配所有元素
anyMath--检查是否至少匹配一个元素
noneMatch--检查是否没有匹配所有元素
findFirst--返回第一个元素
findAny-- 返回当前流中的任意元素
count--返回流中元素的总个数
max--返回流中最大值
min--返回流中最小值
四,规约与收集
规约-- 可以将流中元素结合起来得到一个值。
reduce(T identity,BinaryOerator)
reduce(BinaryOperator)
------------案列-------------------
// 规约--reduce
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0,(x,y)->x+y);
System.out.println(sum);
//统计员工工资总和
Optional<Float> opt = employees.stream().map(Employee::getPrice).reduce(Float::sum);
System.out.println(opt.get());
收集--接收一个 Collector 接口的实现,用于给 Stream 元素汇总的方法
employees.stream().map(Employee::getPrice).collect(Collectors.toList()).forEach(System.out::println);
//平均值
Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getPrice));
System.out.println(avg);
//总合
Double sum1 = employees.stream().collect(Collectors.summingDouble(Employee::getPrice));
System.out.println(sum1);
//最大值
Optional opt1 = employees.stream().collect(Collectors.maxBy((e1,e2)->Float.compare(e1.getPrice(),e2.getPrice())));
System.out.println(opt1.get());
//最小值
Optional opt2 = employees.stream().map(Employee::getPrice).collect(Collectors.minBy(Float::compare));
System.out.println(opt2.get());
//分组
Map<Employee.Status,List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
//多级分组
Map<Employee.Status,Map<String,List<Employee>>> map1 = employees.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e)->{
if(e.getAge()>20){
return "青年";
}else if(e.getAge()>30){
return "中年";
}else{
return "老年";
}
})));
System.out.println(map1);
//分区
Map<Boolean,List<Employee>> map3 = employees.stream().collect(Collectors.partitioningBy(e->e.getAge()>30));
System.out.println(map3);
//Summary 使用
IntSummaryStatistics summary = employees.stream().collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(summary.getMax());
System.out.println(summary.getAverage());
System.out.println(summary.getCount());
// join 拼接
String str = employees.stream().map(Employee::getName).collect(Collectors.joining());
System.out.println(str);
五,并行流 - parallel()
// 20亿 888 毫秒左右
@Test
public void test6(){
Instant start = Instant.now();
Long sum = LongStream.rangeClosed(0L,2000000000L).parallel().reduce(0,Long::sum);
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis());
}
// 对比串行流 20亿 1387 毫秒左右。在往上加到 50 亿,串行流我这里已经跑不动了,但是并行parallel的可以
@Test
public void test7(){
Instant start = Instant.now();
long sum = 0L;
for(int i=0;i<=2000000000L;i++){
sum +=i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis());
}
六,Optional<T> 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
常用方法:
Optional.of(T t); 创建一个 Optional 实例
Optional.empty(); 创建一个空的 实例
Optional.ofNullable(T t); 若 t 不为 null ,常见一个 Optional 实例额,否则创建空实例
isPresent(); 判断是否包含值
orElse(T t); 如果调用对象包含值,返回该值,否则返回 t
orElseGet(Supplier s); 如果调用对象包含值,返回值,否则返回 s 获取值
map(Function f); 如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()
flatMap(Function mapper); 与 map 类似,要求返回必须是 Optional