Java8学习简要笔记
- 内存结构的改变
- 堆中没有了永久区的部分,取而代之为原空间
- java8之前的永久区存储类加载信息,几乎不会被垃圾回收机制回收;Java8之后对应为元空间,使用物理内存(RAM)
- 原来的PremGenSize、MaxPremGenSize在1.8之后删除,取而代之的式MetaSpaceSize、MaxMetaSpaceSize
一、Lambda表达式
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,即Lambda体
1.1 语法格式
-
无参数,无返回值
-
Runnable r1 = () -> System.out.println("Hello, Lambda");
-
一个参数,无返回值,只有一个参数时,小括号可以省略不写,x -> sout(x)
-
Consumer<String> consumer = (x) ->System.out.println(x);
-
多个参数,有返回值,Lambda体中有多条语句。
-
Comparator<Integer> c = (x, y) -> { System.out.println("first"); return Integer.compare(x, y); };
-
多个参数,有返回值,Lambda体中只有一条条语句, return 和 大括号都可以省略
-
Comparator<Integer> c = (x, y) -> {Integer.compare(x, y);
-
Lambda表达式的参数列表的数据类型剋省略不写,JVM编译器通过上下文可以进行推断
1.2 函数式接口
-
接口中只有一个抽象方法,可以使用注解:@FunctionalInterface修饰
-
Lambda表达式需要函数式接口的支持
-
常用的4大内置函数时接口
- Consumer : 消费型接口
- void accept
- Supplier : 供给型接口
- T get();
- Function<T, R> :函数型接口
- R apply(T t);
- Predicate:断言型接口
- boolean test(T t);
- Consumer : 消费型接口
1.3 方法引用、构造器引用
若lambda体中的内容,有方法已经实现了,我们可以使用“方法引用”
方法引用三种语法格式:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
注意:
- Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中方法的参数列表和返回值类型一致。
构造器引用:
- ClassName::new
注意:
- 需要调用的构造器的参数列表要与函数时接口中的方法的参数列表保持一致(决定要初始化的构造函数时有参/无参等)
数组引用:
- Type::new;
Function<Integer, String[]> fun = String[]::new;
String[] strs = fun.apply(10);
1.4 Stream
用于操作数据源(集合、数组等)所生产的元素序列。
集合讲的时数据,流讲的是计算
- Stream不会存储元素
- 不会改变源对象
- 操作是延迟执行的,等到需要结果的(终止操作)时候才会执行,称为“惰性求值”。
三个步骤:
1、创建Stream ——> 2、 中间操作(产生新的流)——> 3、终止操作
-
1、创建Stream的方式:
-
Stream<Employee> stream = InitConst.employees.stream();
-
Arrays.stream(new Employee[10]);
-
Stream<String> stringStream = Stream.of("1", "2");
-
//无限流, 1、迭代 Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
-
// 无线流, 2、生成 Stream<Double> generate = Stream.generate(() -> Math.random());
-
-
2、中间操作:
-
筛选与切片
- filter,接收lambda,从流中排除某些元素
- limit(n),截断流,使元素不超过某个指定的数量
- skip(n),跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流
- distinct,筛选,通过流锁生成元素的hashCode()和equals()去除重复元素
-
映射
-
map,接收Lambda,将元素转换成其他形式或提取信息。接受一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
-
employees.stream().filter(e -> e.getAge() >= 30) .map(Employee::getName ) .forEach(System.out::println);
-
flatMap,接受一个函数作为参数,将流中每个值都换成另一个流,然后把所有流连成一个流。
-
-
排序
- sorted(),自然排序(Comparable)
- sorted(Comparator com),
-
-
3、终值操作:
-
查找与匹配
- allMatch,检查是否匹配所有元素
- anyMatch, 检查是否至少匹配一个元素
- noneMatch,检查是哦福没有匹配的元素
- findFirst,返回第一个元素
- findAny, 返回当前流中的任意元素
- count,返回流中元素的总个数
- max,返回流中最大值
- min,返回流中最小值
- forEach,内部迭代
-
归约
-
reduce(T identity, BinaryOperator),reduce(BinaryOperator),将流中元素反复结合起来,得到一个值
-
// map-reduce模式 Optional<Double> reduce = InitConst.employees.stream() .map(Employee::getSalary) .reduce(Double::sum);
-
-
收集
-
collect,将流转换为其他形式,接受一个Collector接口的实现,用于给Stream中元素做汇总的方法。Collector接口中方法的实现决定了如果对流执行收集操作(收集到List/Map/Set)。Collectors实用类提供了很多静态方法,可以方便的创建常用常见的收集器实例
-
// 收集所有员工的姓名 LinkedHashSet<String> res = InitConst.employees.stream() .map(Employee::getName) .collect(Collectors.toCollection(LinkedHashSet::new));
-
// 收集工资最高的员工信息 Optional<Employee> max = InitConst.employees.stream() .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary)));
-
// 分区,满足条件的进入key为TRUE分区 Map<Boolean, List<Employee>> collect = InitConst.employees.stream() .collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
-
// 字符串拼接 String collect = InitConst.employees.stream() .map(Employee::getName) .collect(Collectors.joining(",", "[", "]"));
-
-
-
1.5 并行流与顺序流
-
Fork/Join框架
将一个大任务,进行拆分(fork)成若干个小任务,再将一个个的小任务运算的结果进行join汇总
- 采用”工作窃取“模式:执行新的任务时,可以将其拆分为更小的任务,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中
public class ForkJoinCalculate extends RecursiveTask<Long> {
@Override
protected Long compute() {}
}
// 调用
ForkJoinPool poll = new ForkJoinPool();
poll.invoke(new ForkJoinCalculate(0L, 90000000000L));
-
并行流
把一个内容分成多个数据块,并用不同的线程分别处理每个数据的流,Stream API可以声明性的通过parallel()与sequential()再并行流和顺序流之间进行切换
1.6 Optional类
1.7 新时间日期Api
不可变,线程安全,java.time包下