《java8实战阅读笔记》
作为一个对java8不是特别理解的人,花了两个星期全面的读了下《java8实战》做了个流水的笔记。
现在线上的java都是基于java8的,以后尽量使用java8的特性编程。
一下的内容都是基于markdown的。。。
# java8 实战
## 2 通过行为参数传递代码
行为的参数化
1 值参数化
2 类,匿名类,lambda
## 3 lambda表达式
lambda表达式
Comparator<Apple> byWeight =(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
函数式接口
仅仅定义了一个抽象方法
函数描述符
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作 函数描述符。
(Apple, Apple) -> int
只有在需要函数式接口的时候才可以传递Lambda
环绕式执行
try{}{
}
java的函数式接口之predicate
test(T t)
函数式接口Consumer
accept(T t)
函数式接口Function
R apply(T t)
抽象方法Supplier
T get()
装箱和非装箱
IntPredicate
IntConsume
int
函数类型检查:符合函数特征即可用
函数变量不推荐使用局部变量,使用时加上final
闭包
闭包就是一个函数的实例,且它可以无限 制地访问那个函数的非本地变量
方法引用
闭包就是一个函数的实例,且它可以无限 制地访问那个函数的非本地变量
三类方法引用
1 静态方法
A::XX
2 指向任意类型实例方法的方法引用
B:xx
3 现有对象的实例方法的方法引用
c:xx
构造函数引用
A::new
List<Integer> weights = Arrays.asList(7, 3, 4, 10);
List<Apple> apples = map(weights, Apple::new);
数组构造函数和父类调用
自动生成比较器
Comparator.comparing((Apple a) -> a.getWeight());
inventory.sort(comparing(Apple::getWeight).reversed());
inventory.sort(comparing(Apple::getWeight)
.reversed()
.thenComparing(Apple::getCountry));
Predicate谓词复合
Predicate<Apple> redAndHeavyAppleOrGreen =
readApple.and(a->a.getWeight() > b.getWeight())
.or(a -> "green".equals(a.getColor()));
function函数复合
andThen,先执行,再执行另外一个函数
先把给定的函数用作compose的参数里面给的那个函 数,然后再把函数本身用于结果。
## 4 流
流的定义
1 java的api
2 声明处理数据集合
3 高级的数据迭代器
流的基本定义
1 元素序列 filter sorted map
2 源。数据源:
3 数据处理操作
filter map reduce find match sort
limit
4 流水线
5 内部迭代
流与集合
1 流只能遍历一次
2 集合的外部迭代,流的内部迭代
流的操作
1 中间操作
filter map limit sorted distinct
2 终止操作
collect
foreach
count
## 5 使用流
谓词筛选
filter
distinct
limit
skip
映射
map
flatmap
查找和匹配
allMatch anyMatch noneMatch
findFirst findAny
optional操作
isPresent
ifPresent
T get()
T orElse(T other)
规约
reduce(init, func)
reduce(min/max)
count
所有的操作
filter
distinct
skip
limit
map
flatMap
sorted
anyMatch
noneMatch
allMatch
findAny
findFirst
forEach
collect
reduce
count
数值流
mapToInt
boxed
IntStream.rangeClosed
构建流
stream.of();
stream.empty();
Arrays.stream(numes);
File.lines(
xxx).distinct().count
函数创建流
stream.iterate
Stream.generate
## 6 使用流收集数据
### 6.1 收集器 & 规约 汇总
总数
Collectors.counting()
最大的 Collectors.maxBy(Comparator.comparingInt(Transaction::getValue))
Collectors.sumInt()
averagingInt
joining
reducie
redcing()
menu.stream().mapToInt(Dish::getCalories).sum();
### 6.2分组
groupingBy 分组,多级分组
按子组收集数据
将收集到的结果转换为另外一种类型collectAndThen
### 6.3 分区
boolean分词作为分区:partitioningBy
collection的静态方法
toList
toSet
toCollection
counting
summingint
averagingInt
joning
maxBy
minBy
reducing
collectionAndThen
groupingBy
partitioningBy
收集器接口
自己实现java的stream
```
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
Function<A, R> finisher();
BinaryOperator<A> combiner();
Set<Characteristics> characteristics();
}
```
## 7 并行数据处理与性能
并行流
parallel
并行流性能影响
1 减少数字的装箱和开箱
2 共享可变状态会影响并行流以及并行计算。
3 如果有疑问需要测量
4 有些操作并行比线性差
5 流水线总成本
6 较小数据量时不适应
7 背后的数据结构是否易于分解
8 中间合并步骤的代价
流的源,可分解性
ArrayList 极佳
LinkedList 差
IntStream.range 极佳
Stream.iterate 差
HashSet 好
TreeSet 好
分支/合并框架
它实现ExecutorService接口,把任务分配给ForkJoinPool
任务实现返回结果:RecursiveTask<R>
不返回结果 RecursiveAction
forkjoin的业务逻辑
```
if (任务足够小或不可分) {
顺序计算该任务
} else {
将任务分成两个子任务
递归调用本方法,拆分每个子任务,等待所有子任务完成
合并每个子任务的结果
}
```
使用分支/合并框架的最佳做法
1 对一个任务调用join方法会阻塞调用方,直到该任务做出结果。两任务均开始后再调用
2 不应该在RecursiveTask内部使用ForkJoinPool的invoke方法。你应该始终直接调用compute或fork方法,只有顺序代码才应该用invoke来启动并行计算。
3 对子任务调用fork方法可以把它排进ForkJoinPool。
4 调试使用分支/合并框架的并行计算可能有点棘手。
5 和并行流一样,你不应理所当然地认为在多核处理器上使用分支/合并框架就比顺序计算快。
原理工作窃取
spliterator 可分迭代器
```
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics();
}
```
## 8 重构,测试和调试
改善可读写和灵活性
1 使用匿名类代替lambda
2 stream的方法引用
3 切换到stream
增加代码的灵活性
1 使用函数式接口
2 延迟执行
3 环绕执行
使用lambda重构设计模式
1 策略模式,函数式接口
2
lambda表达式使用
peek日志调试流
## 9 默认方法
接口可以使用默认反复
默认接口方法冲突的问题
1 类最优
2 子接口最优
3 显示覆盖
## 10 Optional取代null
创建
提取
map 获取Optional里面的数据
flatMap 从其他部分获取Optional
get
orElse
orElseGet
orElseThroww
ifPresent
filer过滤
详细操作
empty
filter
flatMAP
get
ifPresent
isPresent
map
of ofNullable orElse orElseGet orElseThrow
OptionalUtility工具
## 11 CompletableFuture
future工具
```
ExecutorService executor = Executors.newCachedThreadPool(); Future<Double> future = executor.submit(new Callable<Double>() {
public Double call() {
})
try {
Double result = future.get(1, TimeUnit.SECONDS);
} catch (ExecutionException ee) { // 计算抛出一个异常
} catch (InterruptedException ie) { // 当前线程在等待过程中被中断
} catch (TimeoutException te) { // 在Future对象完成之前超过已过期
}
```
future的局限性
1 Future很难直接表述多个Future 结果之间的依赖性,开发中,我们经常需要达成以下目的:
2 将两个异步计算合并为一个(这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果)
3 等待 Future 集合中的所有任务都完成。
4 仅等待 Future 集合中最快结束的任务完成,并返回它的结果。
CompletableFuture
只有当每个操作很复杂需要花费相对很长的时间
基本用法
```
Async结尾的方法都是可以异步执行的,如果指定了线程池,会在指定的线程池中执行,如果没有指定,默认会在ForkJoinPool.commonPool()中执行。下面很多方法都是类似的,不再做特别说明。
四个静态方法用来为一段异步执行的代码创建CompletableFuture对象,方法的参数类型都是函数式接口,所以可以使用lambda表达式实现异步任务
runAsync方法:它以Runnabel函数式接口类型为参数,所以CompletableFuture的计算结果为空。
supplyAsync方法以Supplier<U>函数式接口类型为参数,CompletableFuture的计算结果类型为U。
```
```
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
```
## 12 新的日期和时间API
新的日期库出现的原因
新日期类
LocationDate LocationTime instant Duration period
时间范围 Period Duration
操作和解析
不同时区和历法
## 13 函数式的思考
实现和维护系统
1 类的结构合理
2 提供指标
3 耦合性,内聚性
难题
1 共享的可变数据
命令式编程
声明式编程
称述问题
函数式编程:用函数进行编程的方式
1 修改本地变量
2 只引用不可修改的对象
3 函数或者方法不能抛出异常 使用Option<T>
引用的透明性:同一值,输出不变
面向对象和函数式的对比
1 万物是对象
2 引用透明,不应该有修改对象
考虑编程问题时,采用函数式的方法,关注函数的输入参数以及输出结果
递归和迭代
函数编程不会包含while和for的迭代器
## 14 函数式编程的技巧
### 无处不在的函数
高阶函数:至少一个函数为参数,返回一个函数,注意函数式的副作用
科里化:返回函数
### 持久化数据结构
函数式方法不能修改传入参数或者全局参数
### stream的延迟计算?
stream只允许使用一次
stream不允许递归定义
延迟列表
### 模式匹配
### 杂项
缓存或记忆表
stream的特定
1.stream不存储数据
2.stream不改变源数据
3.stream的延迟执行特性
## 15 面向对象和函数式编程的混合
jvm平台函数式语言 scala
scala 更好的流式编程,更好的函数式编程
## 16 结论以及java的未来
尽量使用新特性