- 1 lambda表达式 [完整笔记](https://blog.csdn.net/PorkBird/article/details/113727704)
- 1.1 定义
- 1.2 细节
- 1.3 格式
- 1.3.1 无参无返回值
- 1.3.2 有参无返回值
- 1.3.3 多个参数、多条语句且有返回值
- 2 函数式接口
- 2.1 定义
- 2.2 自定义函数式接口
- 2.3 与lambda表达式的关系
- 2.4 作为参数传递的lambda表达式
- 2.5 Java 内置四大核心函数式接口
- 2.6 使用场景
- 3 方法引用、构造器引用、数组引用
- 4 Stream API
- 4.1 概述
- 4.2 Stream与Collection的区别
- 4.3 细节
- 4.4 三个步骤
- 4.5 Stream的实例化
- 4.5.1 通过集合
- 4.5.2 通过数组
- 4.5.3 通过Stream的静态方法of
- 4.5.4 创建无限流
- 4.6 Stream的中间操作
- 4.6.1 切片
- 4.6.2 映射
- 4.6.3 排序
- 4.7 Stream的终止操作
- 4.7.1 细节
- 4.7.2 匹配
- 4.7.3 查找
- 4.7.4 规约
- 4.7.5 收集
- 5 Optional类
- 5.1 定义
- 5.2 作用
- 5.3 实例化Optional对象的三种方式
- 5.4 获取Optional容器的对象
- 5.5 判断Optional容器中是否包含对象
- 5.6 实例
java8新特性
1 lambda表达式 完整笔记 1.1 定义Lambda 是一个匿名函数,本质上是函数式接口的实例。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
1.2 细节- 如果方法体中只有1条语句,可以省略{},如果是return语句,必须同时省略return和{};
- 如果参数列表只有一个参数,可以省略();
- 类型推断:参数列表中可以只写变量名,省略数据类型;
- 使用前提:当需要对一个函数式接口实例化时,才可以使用lambda表达式;
-> : lambda操作符或者箭头操作符;
操作符左边:Lambda形参列表(接口中抽象方法的形参列表);
操作符右边:Lambda体(重写的抽象方法的方法体)
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(111);
}
};
r.run();
如果方法体中只有1条语句,可以不用带{};
Runnable r1 = () -> {
System.out.println(2222);
System.out.println("1111");
};
r1.run();
1.3.2 有参无返回值
Consumerc = new Consumer () { @Override public void accept(String s) { System.out.println(s); } }; c.accept("123");
如果只有一个参数,可以不写();
Consumer1.3.3 多个参数、多条语句且有返回值c1 = s -> System.out.println(s); c1.accept("456");
Comparatorc = new Comparator () { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return Integer.compare(o1, o2); } }; int compare = c.compare(10, 8); System.out.println(compare);
Comparatorc1 = (o1, o2) -> { System.out.println(o1); System.out.println(o2); return Integer.compare(o1, o2); }; System.out.println(c1.compare(8, 9));
Comparatorc1 = (o1, o2) -> { return Integer.compare(o1, o2); };
大括号与return必须同时去除;
Comparator2 函数式接口 2.1 定义c1 = (o1, o2) -> Integer.compare(o1, o2);
只包含一个抽象方法的接口称为函数式接口。
2.2 自定义函数式接口@FunctionalInterface是函数式接口的注解,编译时可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
@FunctionalInterface
public interface MyFunctional {
void method();
}
2.3 与lambda表达式的关系
- 在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
- 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
@Test
public void test3() {
method1(new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
}, "abc");
System.out.println("----------------------------");
method1(s -> System.out.println(s), "cde");
}
public void method1(Consumer c, String str) {
c.accept(str);
}
2.5 Java 内置四大核心函数式接口
2.6 使用场景
在开发中,当我们需要定义一个函数式接口时,首先可以看一下jdk中提供的函数式接口是否满足我们的需求,如果满足,直接调用即可。
3 方法引用、构造器引用、数组引用
如果不熟悉方法引用,可以使用lambda表达式。
- Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。
Stream是有关数据计算的,是面向cpu的,通过cpu实现计算;
Collection是静态的内存数据结构,面向内存,用内存存储数据。
- Stream类似于迭代器,本身不存储元素;
- Stream不会改变源对象,它们会返回一个带有结果的新Stream;
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行;
- 实例化Stream对象;
- 中间操作(过滤、映射…);
- 终止操作,一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream stream() : 返回一个顺序流
default Stream parallelStream() : 返回一个并行流
List4.5.2 通过数组list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); Stream stream = list.stream(); Stream integerStream = list.parallelStream();
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static Stream stream(T[] array): 返回一个流
int[] arr = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(arr);
String[] strs = {"a", "b"};
Stream stream1 = Arrays.stream(strs);
4.5.3 通过Stream的静态方法of
public static Stream of(T… values) : 返回一个流
Stream4.5.4 创建无限流integerStream = Stream.of(1, 2, 3, 4, 5);
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
迭代:public static Stream iterate(final T seed, final UnaryOperator f)
生成:public static Stream generate(Supplier s)
4.6.1 切片多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
// filter:筛选
List employees = EmployeeData.getEmployees();
Stream stream = employees.stream();
stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
System.out.println();
// limit:截取前n个元素
employees.stream().limit(4).forEach(System.out::println);
System.out.println();
// skip:跳过前n个元素
employees.stream().skip(3).forEach(System.out::println);
System.out.println();
// distinct:根据流所生成的hashcode和equal去除重复元素
employees.stream().distinct().forEach(System.out::println);
4.6.2 映射
使用映射可以获取流中对象的某个属性,然后使用规约来计算所以对象属性的和。
- map
输出所有员工姓名长度大于3的姓名:先映射获取所有员工的姓名,然后再过滤名字长度小于等于3的 EmployeeData.getEmployees().stream().map(str -> str.getName()).filter(str -> str.length() > 3).forEach(System.out::println);
- flatMap
flatMap(Function f) 相当于List中的addAll方法,addAll是将另一个集合拆分后添加到当前集合中。如果flatMap中的参数是一个Stream,那么会将这个流拆分后添加到当前流中。
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
// list.add(Arrays.asList(4, 5, 6));[1, 2, 3, [4, 5, 6]]
list.addAll(Arrays.asList(4, 5, 6));[1, 2, 3, 4, 5, 6]
System.out.println(list);
public void test10(){
List list = Arrays.asList("aa","bb","cc");
// 使用map:返回值是Stream中嵌套Stream,需要使用双层嵌套去遍历,相当于[[a,a],[b,b],[c,c]]
Stream> streamStream = list.stream().map(this::getCharacter);
streamStream.forEach(s -> s.forEach(System.out::println));
// 使用flatMap:返回值是Stream,直接遍历即可,相当于[a,a,b,b,c,c]
Stream characterStream = list.stream().flatMap(this::getCharacter);
list.stream().flatMap(this::getCharacter).forEach(System.out::print);
}
public Stream getCharacter(String str){
Character[] c = new Character[str.length()];
for (int i = 0; i < str.length(); i++) {
c[i] = str.charAt(i);
}
return Arrays.stream(c);
}
4.6.3 排序
- 自然排序要求生成Stream流的元素必须实现Comparable接口;
- 定制排序
定制排序,需要实现Compactor接口,此处使用方法引用
public void test11() {
List list = Arrays.asList(5, 3, 1, 7, 9);
下面两种输出方式相同,只是lambda表达式可以输出更多内容
list.stream().sorted((Integer::compare)).forEach(o -> System.out.println(o + " "));1 3 5 7 9
list.stream().sorted((Integer::compare)).forEach(System.out::print); 13579
}
对EmployeeData中的元素进行排序,先按年龄进行排序,年龄相同按薪资排序
Stream stream = EmployeeData.getEmployees().stream();
stream.sorted((o1, o2) -> {
int res = Integer.compare(o1.getAge(), o2.getAge());
if (res != 0) {
return res;
} else {
return Double.compare(o1.getSalary(), o2.getSalary());
}
}).forEach(System.out::println);
4.7 Stream的终止操作
4.7.1 细节
- 终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
- 流进行了终止操作后,不能再次使用。
练习:检查所有员工的年龄是否都大于18 Stream4.7.3 查找 4.7.4 规约stream = EmployeeData.getEmployees().stream(); boolean b = stream.allMatch(employee -> employee.getAge() > 18);
public void test12() {
// 规约操作 reduce
// 练习1:计算自然数1-10的和
List list = new ArrayList();
for (int i = 1; i < 11; i++) {
list.add(i);
}
// 第一个参数是初始值,第二个参数是运算规则
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println(reduce);
}
// 计算公司中所有员工的工资总和
Stream stream = EmployeeData.getEmployees().stream();
// 先使用map获取所有员工的工资,然后使用reduce将其累加
Optional reduce = stream.map(employee -> employee.getSalary()).reduce(Double::sum);
System.out.println(reduce);
4.7.5 收集
Collector 接口中方法的实现决定了如何对流执行收集的操作,也就是将stream流转换成其他数据结构(如收集到 List、Set、Map)。
另外, Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
// 练习:查找工资大于6000的员工,结果返回一个List或Set
Stream stream = EmployeeData.getEmployees().stream();
List collect = stream.filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
Set set = stream.filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
5 Optional类
5.1 定义
Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
5.2 作用为了避免空指针异常,使用Optional,不需要再显式判断对象是否为null。
5.3 实例化Optional对象的三种方式- Optional.of(T t):t不能为null;
- Optional.empty():创建一个空的Optional实例;
- Optional.ofNullable(T t):t可以为null;
- T get(): 如果调用对象不为空,返回该值,否则抛异常。
- T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。(一般使用此方法来避免空指针异常)
- T orElseGet(Supplier extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
- TorElseThrow(Supplier extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
- boolean isPresent() : 判断是否包含对象。
- void ifPresent(Consumer super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
Optional



