(个人笔记 水平有限 仅供参考)
我认为Java8中最重要的几个改动:
1.Lambda表达式:(实现了把代码传给方法的方式,能够少些代码,而且可以实现解耦与代码复用,而且看起来很有条理,而且提供了并行以及自定义收集器,而且进行数据的统计的时候非常方便)。
2.函数式编程(将函数作为数据自由传递,结合泛型推导的能力,包括函数式接口(Function/Supplier/Consumer/Predicate等)收集器(Reduce等)与Stream(流))
3.时间日期类的改进(LocalDateTime实在太好用了)
第一章:为什么要关心Java8
1.在Java8中加入Streams可以看作另外两项扩充加入Java8的直接原因:把代码传递给方法的简洁方式(方法引用,Lambda)和接口的默认方法。Streams实现了行为的参数化,只需要把不同的那部分传递进去就可以了,比如计算数组中能被2整除的数的和以及能被3整除的数的和,如果传递进去的是一个Predicate对象的话,就能够比使用策略模式更好用。
2.Java8里面能够将方法传递给代码同时也能够返回代码并将其包含在数据结构中,而且还能让我们使用的一整套新技巧,被称为函数式编程
3.一次编写到处运行,Java的语言(Scala\Groovy)无关性与平台(操作系统层面)无关性。
4.流(A sequence of(一系列的) elements supporting sequential(顺序) and parallel(并行) aggregate(聚合) operations)。流是一连串连续不继的数据的集合,程序可以从流中读取数据,也可以把数据放入流中,一个程序的输出流也可能是另一个程序的输入流。
5.用行为参数化把代码传递给方法。直接传递lambda表达式和方法引用,将方法和lambda作为一等公民(就是编程中的重要角色,以前是值)。
6.并行与可共享的数据(纯函数/无副作用的函数/无状态函数),传递的方法无互动(比方说有可变的共享对象);
7.从侧重改变现有现有值的面向对象思想变成函数式编程领域。
8.foreach(外部迭代)与Stream流的内部迭代
9.对集合的优化处理(需要在某些集合接口中增加新的方法,为了兼容,增加了默认方法)。pipeline()
---Collection是一个集合类型,目的是为各种集合提供最大化的统一操作(default boolean removeIf(Predicate super E> filter) / pipeline(管道)(Abstract base class for "pipeline" classes, which are the core implementations of the Stream interface and its primitive(原始的) specializations(专业化). Manages construction and evaluation of stream pipelines),Collections则包装类,封装了关于集合的多元化操作。
public static
Objects.requireNonNull(spliterator);
return new ReferencePipeline.Head<>(spliterator,
StreamOpFlag.fromCharacteristics(spliterator),
parallel);
}
关于Stream的专业分析见这里:https://blog.csdn.net/zw19910924/article/details/77018798
10.关于Optional
第二章、通过行为参数化传递代码
1.策略设计模式(定义一族算法然后封装起来(称为策略),然后在运行时选择一个算法)。
2.简单工厂方法(工厂->具体产品)/抽象工厂方法(多个产品族)/工厂方法(不同产品)
第三章、Lambda表达式
1.匿名/函数/传递/简洁
2.函数式接口(@functionalinterface)/函数描述符(函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,我们将这种方法叫做函数描述符,例如Runnable接口可以看作是一个什么也不接受什么也不返回的函数签名)。
3.环绕执行模式(try(BufferedReader br=new BufferedReader(new FileReader("data.txt")))){},这样只能够读取1行,如果2行,需要封装成个processFile((BufferedReader br)->br.readLine()+br.readLine())--->所以需要自定义一个功能函数接口并且自主抛出异常(return p.process(br))。
4.几个新的函数式接口:
1.Predicate test()方法 -->T->Boolean
2.Consume的accept()方法--->T->()
3.Supplier的get()方法--->()->T
4.Function的apply()方法----》将T转换成R
5.UnaryOperator
6.BiFunction/BiPredicate/BinaryOperate(Extends BiFunction)(Bi表示接受两个函数返回1个)
5.泛型(伪泛型)+(泛型数组)+(泛型擦除(Object/边界))+频繁的拆装箱(IntPredicate/LongPredicate(泛型特化))
6.任何函数式接口都不允许抛出受检异常(异常分为Error与Exception,Exception分为运行时异常(RuntimeException及其子类)与非运行时异常(编译异常,必须手动抛出捕获异常,否则或报错,如IOException与ClassNotFoundException)),所以需要lambda表达式来抛出异常的话 1.自己通过@FunctionalInterface来定义一个函数式接口,里面定义的方法throws IOException和自己用try/catch来显示定义异常。
7.类型检查/类型推断以及限制( Callable
8.Lambda表达式可以没有限制的捕获实例变量和静态变量,但局部变量有限制(必须显示或者隐式的是final的),也就是只能捕获指派给他们的局部变量一次。(因为实例变量保存在堆里面,堆中可以共享,但局部变量保存在栈里面,而且隐式表明他们仅限于当前线程)。
9.方法引用 Comparator::comparing ArrayList::new 对构造函数进行引用 1个变量 supplier=Constructor::new get 2个变量用function=ConStruction::new apply 3个变量的话可以自己构造可以接受3个变量的Function函数。
10.Lambda表达式的复合(多个Lambda表达式复合成复杂的表达式); 1.比较器复合 Comparing.thenComparing 2.谓词复合and or(从左到右确定优先级)3.函数复合 f.andThen(g)--g(f(x)) f.compose(g)--f(g(x))
第四章、引入流
1.流是一段连续不继的数据的集合。能够减少垃圾变量以及能够并行的运行代码。
2.注意groupingBy()方法的运用:
public staticCollector >> groupingBy(Function super T, ? extends K> classifier){ return groupingBy(classifier, toList());}
public interface Collector
T:表示流中每个元素的类型 A:表示中间结果容器的类型。R:表示最终返回的结果类型