https://www.bilibili.com/video/BV1Kb411W75N?p=666
大处着眼,小处着手。
一:前面:
1.接口增强:可以写 default 方法,静态方法。
默认方法:由子类的对象调用,子类可以重写。
静态方法:由父类.静态方法名 调用,子类不能重写,子类对象不能调用。
2.提供新的 时间 和 日期 API。
3.注解:
类型注解:
重复注解:
4.容器底层变化:集合和map。
5.Java 8 最大的两个改变:
Lambda 表达式 和 Stream API。
二:Lambda 表达式(使代码更简洁)
1. lambda介绍:
lambda 是一个匿名函数,我们可以将 Lambda 表达式,理解为是一段可以传递的代码,
(将代码像数据一样传递)。使用它,可以写出更简洁,更灵活的代码。
2.将来大数据 spark 底层有使用,java8 新特性,比如 Lambda 表达式。
3.举例:
1) 普通写法:
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("我爱北京*,");
} * };
Lambda表达式:
Runnable runnable = () -> System.out.println("123");
2)
4.解释 lambda 表达式:
1)->:Lambda 操作符/箭头操作符
2) 左边:Lambda 形参列表
接口中,抽象方法的形参。其实就是,接口中,抽象方法的形参列表。
右边:Lambda 体:
接口中,抽象方法的方法体。其实就是 抽象方法的 方法体。
3)以前用,匿名实现类 表示的方式 ,现在都可以用 Lambda 表达式来写。
4)Lambda 表达式,就是一个函数式接口的实例。
5.Lambda 表达式分类(6)
1)无参 无返回值:Runnable runnable = () -> System.out.println("123");
2)有参 无返回值:
Runnable runnable = (String str) -> {
sout("123");
}
3)数据类型可以省略,因为可以由编译器 推断得出,称为 “类型推断”
COnsumer<String> con2 = (s) -> {
sout("123");
}
4)Lambda 表达式,若只需要一个参数,参数的小括号可以省略:
COnsumer<String> con2 = s -> {
sout("123");
}
5)Lambda 表达式,需要两个或者以上的参数,多条语句执行,可以有返回值
Comparator<Integer> com = (x,y) -> {
sout("123");
return x+y;
};
6)Lambda 体只有一条语句时,return 或 大括号 都可以可以省略:
Runnable runnable = () -> System.out.println("123");
6.Lambda 表达式 本质:
作为 函数式 接口的实例,
函数时接口的特点就是,只有一个抽象方法。
三:函数式(Functional)接口(Interface)
1.如果一个接口中,只包含 一个抽象方法,此接口,就称为,函数式接口。
2.可以通过 Lambda 表达式,创建 函数式接口 的对象。
3.@FunctionalInterface 注解 :接口上标注,说明此接口,是函数事接口,
不是函数式接口,报错,也可以起到检验是否是函数式接口的作用。
4.Java 内置 ,四大核心 函数式接口:
参数类型 返回类型 用途
1)COnsumer<T> T void void accep(T t)。对类型为 T 的对象 应用操作,包含方法:
消费型接口
2)Supplier<T> 无 T T get()。返回类型为 T 类型,包含方法
供给型接口
3)Function<T,R> T R R apple(T t)。对 类型 T 的对象应用操作,并返回 R 类型对象
函数型接口
4)Predicate<T> T Boolean boolean test(T t)。确定类型为 T 的对象,是否满足约束,
断定型接口
四:方法引用 与 构造器引用(用于替换 Lambda 表达式)
1.方法引用
1)方法引用举例:
1.Lambda表达式 表示:
Comparator<Integer> comparator1 = (o1, o2) -> Integer.compare(o1, o2);
2.方法引用 表示:
Comparator<Integer> comparator2 = Integer::compareTo;
2)方法引用使用场景:
当要传递给 Lambda体 的操作,已经有实现的方法了,可以使用方法引用。
方法引用,可以看做是,Lambda 表达式,更深层次的表达。
换句话说:方法引用本质 就是 Lambda 表达式,也就是函数式接口的一个实例。
3)使用格式:
通过 方法的名字,来指向一个方法,可以认为是 Lambda 表达式 的一个语法糖。
类/对象 :: 方法名
4)具体分为 三种情况
1.对象 :: 非静态方法
2.类 :: 静态方法
3.类 :: 非静态方法
5)使用场景要求:
1.要求接口中的,抽象方法的 形参列表 和 返回值类型,
与 方法引用的 方法的 形参列表 和 返回值类型相同。
2.构造器引用
1)构造器引用举例:
1.Lambda表达式 表示:
Supplier<Employee> employeeSupplier = () -> new Employee();
2.方法引用 表示:
Supplier<Employee> employeeSupplier1 = Employee::new;
2)要求:
和方法引用类似,函数式接口的 抽象方法的 形参列表 和 构造器 形参列表一致,
抽象方法的返回值类型 即为 构造器 所属的类的类型。
3.数组引用:
五:强大的 Stream API(对内存中数据操作)
0.介绍
1)并行流:
就是将一个内容,分成多个数据块,并用不同的线程,分别处理
每个数据块的流。
相比于串行流,并行流可以很大程度上提高程序的执行效率。
2)串行流:
1.Stream 介绍
1) java 8 重要的改变,Stream API 真正的把 函数式编程风格,引入到java 中,
简化了对集合的操作,可以执行复杂的 查找、过滤 和 映射数据 等操作。
2)为什么使用 Stream API:?
实际开发中,项目中多数数据源都来自 mysql,oracle等数据库,
但现在,数据源更多了,有 MongDB,Redis等,而这些,NoSQL 的数据,
就需要java 层面来处理了。
3)Stream 和 Collection 区别:
Collection :
是一种 静态的内存数据结构,主要是对数据的存储。
主要是面向内存,存储到内存中。
而 Stream :(数据渠道)
是有关计算的,用于操作数据源 所生成的 元素序列。
主要面向 CPU,通过 CPU 计算实现。
4)注意:
1.Stream 不会自己存储数据
2.Stream 不会改变源对象。相反,他们会返回一个,持有结果的新 Stream
3.Stream 操作是延迟执行的。这意味着,他们会等到需要结果的时候,才运行。
2.Stream 操作有三个步骤:
1)创建 Stream:
根据 数据源(如:集合,数组),获取一个 对应的流。
2)中间操作:
一个中间操作链,对数据源的数据,进行处理。
3)终止操作(终端操作)
一旦执行 终止操作,才会执行 中间操作链 ,并产生结果,之后不会在被使用。
3.Stream 创建对象操作(4)
1)通过集合创建:
//1.通过集合创建 Stream
List<Employee> employees = EmployeeData.getEmployees();
//顺序流:根据集合,获取一个顺序流,按照集合中顺序来
Stream<Employee> stream = employees.stream();
//并行流:根据集合,获取一个并行流,集合中并行取数据
Stream<Employee> employeeStream = employees.parallelStream();
2) //通过数组创建 Stream
int[] a = new int[]{21321,323,323,2323,232,332,3,23,2,3,2};
IntStream stream = Arrays.stream(a);
3) //通过 Stream 的 of
Stream<Integer> integerStream = Stream.of(1, 2, 32, 32, 34);
Stream<String> fdsf = Stream.of("fdsf", "afdsf", "sadf");
4) //创建无限流,可以造数据。
//迭代:遍历 前十个 偶数
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成:
Stream.generate(Math::random).limit(10).forEach(System.out::println);
4.Stream 的中间操作(3):多个中间操作,可以连接起来一个链,形成一个流水线。
1)筛选与切片
1.过滤:filter(Predicate p):接收Lambda,从流中排除数据
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
//从流中,筛选出 年龄 大于 10 的数据
stream.filter(e -> e.getAge() > 10).forEach(System.out::println);
2.limit(int a):截断流,使其元素不会超过给定数量
Stream<Employee> stream1 = employees.stream();
stream1.limit(2).filter(e->e.getAge()>10).forEach(System.out::println);
3.skip(n):跳过元素,返回一个扔掉了,前 n 个元素的流。若超过,返回空
Stream<Employee> stream2 = employees.stream();
stream2.skip(30).forEach(System.out::println);
4.distinct():筛选,通过流 所生成元素的 hashcode() 和 equals() 去除重复元素
Stream<Employee> stream3 = employees.stream();
stream3.distinct().forEach(System.out::println);
2)映射:
1.Map(Function f):接收一个函数,作为参数,将元素转换成 其他形式或提取信息,
该函数,将会被应用到 每个元素上,并将其映射成一个新的元素。
可以 将 list 里面的元素,挑选出来,转换为list<元素>的集合。
//将 list 里面字母,转换为大写
List<String> strings = Arrays.asList("fasdf", "dsf", "fdsd");
Stream<String> stream = strings.stream();
stream.map(str -> str.toUpperCase()).forEach(System.out::println);
//获取员工姓名大于 3 的员工
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream1 = employees.stream();
Stream<String> stringStream = stream1.map(e -> e.getName());
stringStream.forEach(System.out::println);
Stream<String> stringStream1 = stringStream.filter(name -> name.length() > 3);
2.flatMap(Function f):接收一个函数作为参数,将流中的每个值,都换成另一个流。
然后把,所有流,连成一个流。
1)
2)
3)
3)排序:
1.sorted():
1)产生一个 新流,其中 按照自然顺序 排序。
2)示例:
List<Integer> integers = Arrays.asList(123, 23122, 3, 123);
Stream<Integer> stream = integers.stream();
Stream<Integer> sorted = stream.sorted();
sorted.forEach(System.out::println);
2.sorted(Comparaotr com):
1)产生一个新流,其中按比较器 顺序排序。
2)示例:
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> sorted =
employees.stream().sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
sorted.forEach(System.out::println);
3)如果排序相同,可以按照第二个字段排序:
int a = Integer.compare(e1.getAge(), e2.getAge());
if (a != 0) {
return a;
} else {
return Integer.compare(e1.getAge(),e2.getAge());
}
5.终止操作:
1)匹配与查找:
1.判断是否都
//判断 流 里的对象的 年龄 是否都大于 18 岁
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
boolean b = stream.allMatch(e -> e.getAge() > 200);
System.out.println(b);
2.检查是否至少匹配一个(查看是否存在)
//判断 是否讯在 年龄 小于 33
boolean b1 = stream.anyMatch(e -> e.getAge() < 33);
3.检查是否没有匹配元素(没有匹配元素 为 true)
boolean b = stream.noneMatch(employee -> employee.getAge() < 0);
4.返回第一个元素
Optional<Employee> first = stream.findFirst();
5.返回任意一个元素
Optional<Employee> any = stream.findAny();
6.求流中 元素总个数
long count = stream.filter(e -> e.getAge() < 400).count();
7.查找 流中最大值
Optional<Employee> max = stream.max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
8.内部迭代(对于流的终止操作)
stream.forEach(System.out::println);
集合里(普通方法)
list.forEach(System.out::println);
2)规约:
1.reduce():可以将 流中的元素 反复结合起来,得到一个值,返回。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println(reduce);
或者
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> reduce = list.stream().reduce(Integer::sum);
System.out.println(reduce);
3.求 所有员工 工资和:
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Integer reduce1 = stream.map(e -> e.getAge()).reduce(0, Integer::sum);
System.out.println(reduce1);
或者
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Optional<Integer> reduce1 = stream.map(e -> e.getAge()).reduce((d1, d2) -> d1 + d2);
System.out.println(reduce1);
3)收集
1.collect(Collector c)
将 流 转换为 其他形式,手机一个 Collector 接口的实现,用于给 Stream 中 元素做汇总的方法。
Collector 接口中,方法的实现,决定了如何对流,执行收集的操作(如:收集到 List,Set,Map)。
另外,Collector 类,提供了很多静态方法,可以方便的创建,常见收集器实例。
2.将 过滤后的流,转换为 List 集合:
List<Employee> collect = stream.filter(e -> e.getAge() > 100).collect(Collectors.toList());
六:Optional 类(最大化减少空指针异常)
1.
2.
3.
4.