Lambda表达式
自Java1.0以来,已经增加了许多功能,其中两个最为突出,对java语言产生了深远影响,从根本上改变了代码的编写方式。第一是JDK5增加的泛型,第二是Lambda表达式
Lambda表达式是JDK8新增加的功能,它显著增强了Java,原因有两个.一,它们增加了新的语法元素,使java语言的表达能力得以提升,并流线化一些常用结构的实现方式;二,导致API库增加了新的功能,包括利用多核环境并行处理功能(尤其是处理for-earch风格)变得更加容易,以及支持对数据执行管道操作的新的流API.催生了新的Java功能,默认方法。
几年前泛型重塑了java,如今lambda表达式正在重塑java
理解lambda表达式的java实现,两个结构十分关键:第一lambda表达式自身,第二函数式接口
Lambda表达式本身就是一个匿名方法。但是这个方法不是独立执行的,而是用于实现由函数式接口定义的另一个方法,因此,lambda表达式会导致产生一个独立匿名类。Lambda表达式也常被称为闭包
函数式接口是仅包含一个抽象方法的接口。这个方法指明了接口的目标用途。函数式接口通常表示单个动作。例如Runnable是一个函数式接口。此外函数式接口定义了lambda表达式的目标类型。有时被称为SAM类型,单抽象方法(Single Abstracted Method)
Lambda表达式在Java语言中引入了操作符->,它将lambda表达式分为两个部分。左侧lambda表达式需要的所有参数(可以为空),右侧指定lambda体,表达式要执行的动作。
两种lambda体。一种包含单个表达式,另一种包含一个代码块。
从JDK8开始,可以为接口声明的方法指定默认行为,即默认方法。只有当没有指定默认实现时,接口方法才是抽象方法。
Lambda表达式不是独立执行的,而是构成了一个函数式接口定义的抽象方法的实现,该函数式接口定义了它的目标类型。只有在定义里lambda表达式的目标类型的上下文中,才能使用该表达式。当把lambda表达式赋给一个函数式接口引用时,就创建了这样的上下文。
Lambda表达式提供了一种将代码片转换为对象的方法
对于lambda表达式中的多个参数,如果需要显示声明一个参数的类型,那么必须为所有的参数声明类型
Lambda体只包含单个表达式,被称为表达式体,有时也被称为表达式lambda。由代码块构成的被称为块lambda
块lambda必须显示使用return语句来返回值
Lambda体本质上与方法体类似。
Lambda表达式自身不能指定类型参数,因此lambda表达式不能是泛型。(然而,由于存在类型推断,所有lambda表达式都展现出一些类似与泛型的特征),与lambda表达式关联的函数式接口可以是泛型
Lambda表达式可以使用或修改其调用类的实例变量,只是不能使用其外层作用域内的具备变量,除非该变量实质上是final变量
方法引用提供了一种引用而不执行方法的方式
静态方法的方法引用
ClassName::methodName
实例方法的方法引用
泛型中的方法引用
构造函数引用
classname::new
要为数组创建构造函数引用 type[]::new
在很多时候,并不需要自己定义函数式接口,因为JDK8中包含了新包java.util.function,其中提供了一些预定义的函数式接口
并发实用工具
原始的多线程支持并没有提供一些高级特性,比如信号量、线程池以及执行管理器,这些特性有助于创建强大的并发程序
并发程序是指广泛而完整地执行多个并发线程的程序
JDK5增加了并发实用工具,通常也被称为并发API。例如同步器(比如信号量)、线程池、执行管理器、锁、一些并发集合以及使用线程获取计算结果的流线化方式
JDK7对之进行了极大扩展。最重要的新增内容是Fork/Join框架。Fork/Join框架使得创建使用多个处理器的程序更加容易,因而简化了两个或多个片真正同时执行,而不仅仅是时间切片这类程序的创建
因为多核系统的不断普及,涉及Fork/Join框架的解决方案变得更加普遍
同步器、执行器、并发集合、Fork/Join框架
同步器提供了同步多线程间交互的高级方法
执行器管理线程的执行,执行器层次的顶部是Executor接口,该接口用于启动线程。ExecutorService扩展了Executor,并提供了管理执行的方法。与执行器相关的是Future和Callable接口
并发集合类:ConcurrentHashMap、ConcurrentLinkedQueue和CopyOnWriteArrayList
Fork/Join框架支持并行编程,包含的类有ForkJoinTask、ForkJoinPool、RecursiveTask以及RecursiveAction
Semaphore实现率经典的信号量。信号量通过计数器控制对共享资源的访问
CountDownLatch在初始创建时带有事件数量计数器,在释放锁存器之前,必须发生指定数量的事件
CyclicBarrier,直到指定数量的线程都到达界限点为止,才开始执行
Exchanger设计目的是简化两个线程之间的数据交换
Phaser该类的主要目的是允许表示一个或多个活动阶段的线程进行同步
使用执行器,用于启动并控制线程的执行,核心是Executor接口,定义的方法
void execute(Runnable thead)
ExecutorService接口通过添加用于帮助管理和控制线程执行的方法,对Executor接口进行了扩展
执行器还定义了ScheduledExecutorService接口,扩展了ExecutorService以支持线程调度
3个执行器类:ThreadPoolExecutor、ScheduledThreadPoolExecutor以及ForkJoinPool
尽管可以直接使用ThreadPoolExecutor和ScheduledThreadPoolExecutor,但是绝大数情况下,会希望调用Executors实用工具类定义的静态工厂方法来回去执行器
Callable泛型接口表示返回值的线程
Future泛型接口表示将由Callable对象返回的值
当多个线程需要访问共享数据时,锁特别有用,锁是一些对象,它们为使用Synchronized提供了替代技术,工作原理:在访问共享资源之前,申请用于保护资源的锁;当资源访问完成时,释放锁。当某个线程正在使用锁时,如果另一个线程尝试申请锁,那么后者会被挂起,
原子操作
通过Fork/Join框架进行并行编程
JDK7增加了一些支持并行编程的类和接口。它们通常被称作Fork/Join框架,通过两种方式增强多线程编程,首先简化了多线程创建和使用,其次Fork/Join框架自动使用多处理器
通过Fork/Join框架,应用程序能够自动伸缩,以利用可用数量的处理器
传统多线程与并行编程之间的区别:在单核cpu系统中,多线程编程用于允许两个或多个任务共享cpu,没有对可以使用两个或更多个cpu的情况进行优化
并行编程能够显著提高程序的性能
主要的Fork/Join类: ForkJoinTask<V>、ForkJoinPool、RecursiveAction、RecusiveTask<V>
ForkJoinPool使用一种称为工作挪用(Work stealing)的方式来管理线程的执行
ForkJoinPool使用守护线程。
分而治之的策略,作为通用规则,使用Fork/Join框架会用到基于递归的粉儿治之的策略。
策略:将任务递归的划分成为更小的子任务,直到子任务足够小,从而能够被连续的处理为止。直到达到临界点为止,在该临界点,连续的解决方案比进行另一次划分更快
分而治之策略的优势在于处理过程可以并行发生。通常最佳临界点是通过配置执行特征获得的,最好避免使用过大或过小的临界点。根据经验任务应当在100到10000个计算步骤之间的某个位置执行
对于将在已知系统中运行的应用程序来说,处理器的数量已知,所以可以使用处理器的数量来决定临界点的选取
JDK8存在ForkJoinPool公共池
提高处理速度可以在计算机上试验不同的临界点和运行级别
为了更好地利用Fork/Join框架,任务应当执行计算,这些计算在没有外部阻塞或同步时就能运行。
不要对代码将在其中运行的环境做出假设(不应当假定可用处理器的某个特定数量、不受外部进程的影响),Fork/Join框架为将并行编程技术集成到更复杂的应用程序中提供了不错的方式
转载请注明:学时网 » java8学习笔记总结(五)