目录
(3)数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
(5)Lambda需要两个或以上参数,多条执行语句,并且有返回值
(6)当Lambda体只有一条语句时,return与大括号若有,都可以省略
java8可以优化代码编写效率,需要学习一下。
一、java8新特性概览
- 速度更快
- 代码更少(Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常:Optional
- Nashorn引擎,允许在JVM上允许JS应用
二、Lambda表达式
1.Lambda表达式格式
@Test
public void test2(){
//常规写法
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare1 = com1.compare(12,21);
System.out.println(compare1);
//Lambda表达式
Comparator<Integer> com2 = (o1,o2)->Integer.compare(o1,o2);
int compare2 = com2.compare(12,21);
System.out.println(compare2);
//方法引用
Comparator<Integer> com3 = Integer::compareTo;
int compare3 = com3.compare(12,21);
System.out.println(compare3);
}
格式:(o1,o2)->Integer.compare(o1,o2)
解析:
- ->:Lambda操作符或者叫箭头操作符
- 左边:Lambda形参列表(其实就是接口中的抽象方法的形参列表)
- lambda形参列表的参数类型可以省略(类型推断),如果形参只有一个,括号也可省略
- 右边:Lambda体(其实就是重写的抽象方法的方法体)
- Lambda体一般来说用大括号包起来,如果只有一条语句,可以省略大括号(如果一条语句有返回值,还可以省略return)
2.Lambda表达式的本质
作为函数式接口的实例
3.Lambda表达式的使用
(1)无参、无返回值
Runnable r2 = () ->{System.out.println("xpxp");}
(2)有参、无返回值
Consumer<String> con1 = (String s)->{System.out.println(s);}
(3)数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
Consumer<String> con1 = (s)->{System.out.println(s);}
注:类型推断很好理解,我们在其他地方也遇到过类型推断:
//类型推断
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> list = new ArrayList<>();
//类型推断
int[] arr = new int[]{1,2,3};
int[] arr = {1,2,3};
(4)Lambda若只需要一个参数时,参数的小括号可以省略
Consumer<String> con1 = s->{System.out.println(s);}
(5)Lambda需要两个或以上参数,多条执行语句,并且有返回值
Consumer<Integer> con1 = (o1,o2)->{
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
(6)当Lambda体只有一条语句时,return与大括号若有,都可以省略
Consumer<Integer> con1 = (o1,o2)->o1.compareTo(o2);
三、函数式(Function)接口
1.什么是函数式接口
- 只包含一个抽象方法的接口,称为函数式接口
- 在接口上使用@FunctionalInterface注解,这样可以检查是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口
- 在java.util.function包下定义了java8的丰富函数式接口
2.java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
Consumer<T> 消费型接口 |
T | void | 对类型为T的对象应用操作,包含方法: void accept(T t) |
Supplier<T> 供给型接口 |
无 | T | 返回类型为T的对象,包含方法:T get() |
Function<T,R> 函数型接口 |
T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象 包含方法:R apply(T t) |
Predicate<T> 断定型接口 |
T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值 包含方法:boolean test(T t) |
3.其他函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
BiFunction<T,U,R> | T,U | R | 对类型为T,U参数应用操作,返回R类型的结果 包含方法为:R apply(T t,U u) |
UnaryOperator<T> (Function子接口) |
T | T | 对类型为T的对象进行一元运算,并返回T类型的结果 包含方法为:T apply(T t) |
BinaryOperator<T> (BiFuncation子接口) |
T,T | T | 对类型为T的对象进行二元运算,并返回T类型的结果 包含方法为:T apply(T t1,T t2) |
BiConsumer<T,U> | T,U | void | 对类型为T,U参数应用操作 包含方法为:T apply(T t,U u) |
BiPredicate<T,U> | T,U | boolean | 包含方法为:boolean test(T t,U u) |
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> |
T | int long double |
分别计算int、long、double值得函数 |
IntFunction<R> LongFunction<R> DoubleFunction<R> |
int long double |
R | 参数分别为int、long、double类型的函数 |
四、方法引用
1.使用情景
当要传递给lambda体的操作,已有实现的方法,可以使用方法引用
2.方法引用的实质
方法引用的实质就是函数式接口的实例
3.使用格式
类(或对象)::方法名
4.具体的使用情况
(1)对象::非静态方法
(2)类::静态方法
(3)类::非静态方法
注:针对(1)和(2),要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法形参列表和返回值类型要相同
五、构造器、数组引用
1.构造器引用格式
类名::new
2.构造器引用使用要求
函数式接口的形参和返回值要和构造器的一致
3.数组引用格式
数字类型[]::new
六、Stream API(重要)
使用Stream API对集合数据进行操作,类似于使用sql执行数据库的查询
注:每个流只能用一次
1.什么是Stream
是数据渠道,用于操作数据源(集合、数组)所生成的元素序列。集合讲的是数据,Stream讲的是计算
- Stream自己不会存储数据
- Stream不会改变源对象,相反,它们会返回一个持有结果的新Stream
- Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行
2.Stream操作的三个步骤
- 创建Stream:一个数据源(集合、数组),获取一个流
- 中间操作:一个中间操作链,对数据源的数据进行处理
- 终止操作:一旦执行终止操作,就执行中间操作链并返回结果,之后不会再被使用
3.创建Stream
(1)通过集合
List<String> list = new ArrayList();
//返回一个顺序流(有顺序)
Stream<String> stream = list.stream();
//返回一个并行流(无序,效率更高)
Stream<String> stream = list.parallelStream();
(2)通过数组
除了IntStream,还有LongStream、DoubleStream等:
int[] arr = new int[]{1,2,3};
//返回流
IntStream stream = Arrays.stream(arr);
(3)通过Stream的of()
Stream<Integer> stream = Stream.of(1,2,3);
(4)创建无限流
//迭代:遍历前10个偶数
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成10个随机数
Stream.generate(Math::random).limit(10).forEach(System.out::println);
4.中间操作
(1)筛选与切片
//员工list,假设有数据
List<Employee> list = new ArrayList();
//filter过滤:从流中排除某些元素
list.stream().filter(e->e.getSalary()>7000).forEach(System.out::println);
//limit截断:使元素不超过给定数量
list.stream().limit(3).forEach(System.out::println);
//skip跳过:返回一个扔掉了前n个元素的流,若不足n,则返回空流
list.stream().skip(3).forEach(System.out::println);
//distinct筛选:通过流所生成的hashCode()和equals()去除重复元素
list.stream().distinct().forEach(System.out::println);
(2)映射
List<Employee> list = new ArrayList();
//map:接受一个函数作为参数,将元素转化为其他形式或提取信息。该元素会被应用到每个元素上,并将其映射成一个新的元素
Stream<String> nameStream = list.stream().map(Employee::getName);
nameStream.filter(name->name.length()>3).forEach(System.out::println);
//flatMap:接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
//map和flatMap区别:
//简单来说,以json为例,map是会变成多层json的结构。而flatMap只会有一层的json结构,且以最后面一层展开
//如果当前有一个操作把string集合变成List<String>集合,即{aa,bb,cc}=>{
{a,a},{b,b},{c,c}}(相当于json一层变成两层),假设该方法在Test1类下的方法名为change(str)
//如果使用map:
Stream<Stream<Character>> streamStream = list.stream().map(Test1::change);
streamStream.forEach(s->{
s.forEach(System.out::println);
});
//如果使用flatMap
Stream<Character> characterStream = list.stream().flatMap(Test1::change);
characterStream.forEach(System.out::println);
(3)排序
//自然排序
List<Integer> list = Arrays.asList(1,3,2);
list.stream().sorted().forEach(System.out::println);
//定制排序
List<Employee> employeeList = new ArrayList();
//只根据年龄排序
employeeList.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);
//根据多个条件排序
employeeList.stream().sorted((e1,e2)->{
int ageValue = Integer.compare(e1.getAge(),e2.getAge());
if(ageValue !=0){
return ageValue ;
}else{
return Double.compare(e1.getSalary(),e2.getSalary());
}
}).forEach(System.out::println);
5.终止操作
(1)匹配与查找
List<Employee> employeeList = new ArrayList();
//allMatch:检查是否匹配所有元素
boolean allMatch = employeeList.stream().allMatch(e->e.getAge()>18);
//anyMatch:检查是否至少匹配一个元素
boolean anyMatch= employeeList.stream().anyMatch(e->e.getAge()>18);
//noneMatch:检查是否没有元素匹配
boolean noneMatch= employeeList.stream().noneMatch(e->e.getAge()>18);
//findFirst:返回第一个元素
Optional<Employee> employee = employeeList.stream().findFirst();
//findAny:返回当前流中任意元素
Optional<Employee> employee = employeeList.stream().findAny();
//count:返回流中元素的总个数
long count = employeeList.stream().filter(e->e.getSalary()>3000).count();
//max:返回流中最大值
Optional<Double> s= employeeList.stream().map(e->e.getSalary()).max(Double::compare)
//min:返回流中最小值
Optional<Employee> employee = employeeList.stream().min((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()))
//forEach:内部迭代
employeeList.forEach(System.out::println)
(2)归约
//reduce:将流中元素反复结合起来,得到一个值,返回
//计算自然数和
List<Integer> list = Arrays.asList(1,2,3);
//这里的0表示初始值,sum = 初始值 + 自然数和,用于累加
Integer sum = list.stream().reduce(0,Integer::sum);
//计算工资之和
List<Employee> employeeList = new ArrayList();
Option<Double> sumMoney1 = employeeList.stream().map(Employee::getSalary).reduce(Double::sum);
Option<Double> sumMoney2 = employeeList.stream().map(Employee::getSalary).reduce((d1,d2)->d1+d2);
(3)收集
List<Employee> employeeList = new ArrayList();
//collect:将流转化为其他形式的Collector
List<Employee> list = employeeList.stream().filter(e->e.getSalary()>6000).collect(Collectors.toList());
Set<Employee> set= employeeList.stream().filter(e->e.getSalary()>6000).collect(Collectors.toSet());
七、Optional
Optional类是一个容器类,可以保存类型为T的值,代表这个值存在。也可以保存null,代表这个值不存在,但是不会报空指针。
(1)创建Optional类对象的方法
//Optional.of(T t):创建一个Optional实例,t必须为非空
//Optional.empty():创建一个空Optional实例
//Optional.ofNullable(T t):t可以为空
(2)判断Optional类对象是否包含对象
//判断是否包含对象
boolean isPresent()
(3)获取Optional容器的对象
//获取Optional容器的对象,如果有值返回,否则抛异常
T get()
//如果没有值,则返回指定other对象
T orElse(T other)
八、打赏请求
如果本篇博客对您有所帮助,打赏一点呗,谢谢了呢~