《实战Java高并发程序设计》读书笔记六
第六章 Java 8 与并发
1、函数式编程
函数作为一等公民:
- 将函数作为参数传递给另外一个函数这是函数式编程的特性之一。
- 函数可以作为另外一个函数的返回值,也是函数式编程的重要特点。
无副作用:
- 函数的副作用是指在函数调用过程中除了给出了返回值以外还修改了其他函数的外部状态。
申明式:
- 函数式编程是申明式编程,不再需要提供明确的指令操作,所有细节指令将会更好的被程序库所封装,只要提出要求申明用意即可。
不变的对象:
- 在函数式编程中,几乎所有传递的对象都不会被轻易修改。
易于并行:
- 由于对象都处于不变的状态,因此函数式编程更加易于并行。
更少的代码:
- 通常情况下,函数式编程更加简明扼要,精简的代码更易于维护。
2、函数式编程基础
FunctionalInterface注释:
- Java 8 提出了函数式接口的概念。函数式接口就是只定义了单一抽象方法的接口,如果符合这个定义即使没有使用注释编译器也会把他看做函数式接口。
- 函数式接口是只能有一个抽象方法,而不是只能有一个方法。其次任何被Object实现的方法都不能视为抽象方法。
- 函数式接口可以由方法引用或者lambda表达式进行构造。
接口默认方法:
- Java 8之前接口只能包含抽象方法,但在Java 8 后接口可以包含若干个使用default修饰的实例方法。
- 接口默认方法会带来多继承的问题,继承的接口有两个一样的方法时需要重写这个方法指定调用那个接口的方法。
lambda表达式:
- lambda是函数式编程的核心,lambda表达式即匿名函数,是一段没有函数名的函数体,可以作为参数直接传递给相关的调用者
方法引用:
- 方法引用是Java 8 中提出的用来简化lambda表达式的手段,它通过类名和方法名来定位到一个静态方法或者实例方法。
- 静态方法引用:ClassName::methodName
- 类型上的实例方法引用:ClassName::methodName
- 构造方法的引用:ClassName::new
- 实例上的实例方法引用:instanceReference::methodName
- 超类上的实例方法引用:super::methodName
- 数组构造方法引用:TypeName[]::new
package com.ecut.lambda; import java.io.Serializable; public class User implements Serializable { private int id; private String name; public User(int id , String name){
this.id = id ;
this.name = name ;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}package com.ecut.lambda; import java.util.ArrayList;
import java.util.List; public class LambdaTest { @FunctionalInterface
interface UserFactory<U extends User> {
U creat(int id, String name);
} static UserFactory<User> userFactory = User::new; public static void main(String[] args) {
List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
users.add(userFactory.creat(i, "user" + Integer.toString(i)));
}
users.stream().map(User::getName).forEach(System.out::println);
}
}UserFactory作为User的工厂类是一个函数式接口。当使用User::new创建接口实例时,系统会UserFactory.create()的函数签名来选择合适的User构造函数签名来选择合适的User构造函数。在创建UserFactory实例后,对UserFactory.create()的调用都会委托给User的实际构造函数进行,从而创建User对象实例。
3、走入函数式编程
函数式编程测试案例:
package com.ecut.lambda; import java.util.Arrays;
import java.util.function.IntConsumer; public class HelloLambaTest {
static int[] arr = {1, 2, 3, 4, 5}; public static void main(String[] args) {
//普通输出
for (int i : arr) {
System.out.println(i);
}
/*使用Java 8中的流 Arrays.stream返回了一个流对象。类似于集合或者数组。foreach接受了一个IntConsumer接口的实现用于对流内部
对象的处理*/
Arrays.stream(arr).forEach(new IntConsumer() {
@Override
public void accept(int value) {
System.out.println(value);
}
}); //省略foreach参数
Arrays.stream(arr).forEach((final int value) -> {
System.out.println(value);
}); //省略参数类型
Arrays.stream(arr).forEach((value) -> {
System.out.println(value);
}); //使用lambda表达式,省略括号
Arrays.stream(arr).forEach(value -> System.out.println(value)); //使用方法引用
Arrays.stream(arr).forEach(System.out::println); }
}
lambda不仅可以简化匿名类的编写与接口默认方法相结合还可以使用流畅的流式API对各种组件进行更自由的装配。
//流式API
IntConsumer out = System.out::println;
IntConsumer err = System.err::println;
Arrays.stream(arr).forEach(out.andThen(err));
4、并行流和并行排序
并行流过滤数据:
package com.ecut.lambda; import java.util.stream.IntStream; public class ParallelFilterTest { public static boolean isPrime(int number){
int tmp = number ;
if(tmp < 2){
return false;
}
for (int i = 2 ; Math.sqrt(tmp) >= i ; i++){
if(tmp % i == 0) {
return false;
}
}
return true;
} public static void main(String[] args) {
long count = IntStream.range(1,1000000).parallel().filter(ParallelFilterTest::isPrime).count();
System.out.println(count);
}
}
从集合得到并行流:
package com.ecut.lambda; import java.util.ArrayList;
import java.util.List; public class ParallelStreamTest {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
users.add(new User(i, "user" + i));
}
double avg = users.parallelStream().mapToInt(User::getId).average().getAsDouble();
System.out.println(avg);
}
}
并行排序:
package com.ecut.lambda; import java.util.Arrays; public class ParallelSortTest {
public static void main(String[] args) {
int[] arr = {8, 5 ,7,2,9,1};
Arrays.parallelSort(arr);
for(int i = 0 ; i < arr.length ; i++){
System.out.println(arr[i]);
}
}
}
5、增强的Future CompletableFuture
可以手动设置CompletableFuture的完成状态:
package com.ecut.completablefuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; public class CompleteTest {
public static class AskThread implements Runnable { private CompletableFuture<Integer> completableFuture = null; public AskThread(CompletableFuture<Integer> completableFuture) {
this.completableFuture = completableFuture;
} @Override
public void run() {
try {
// CompletableFuture中没有数据,处于未完成状态
System.out.println(completableFuture.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
CompletableFuture<Integer> completableFuture = new CompletableFuture<>();
//没有数据,请求线程一直等待
new Thread(new AskThread(completableFuture)).start();
//手动设置完成结果
completableFuture.complete(1);
}
}
异步执行任务:
package com.ecut.completablefuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; public class AsyncTest { private static Integer calc(Integer para){
try {
//模拟长时间的计算过程
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return para*para;
} public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->calc(60));
System.out.println(completableFuture.get());
}
}
流式调用:
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(()->calc(60)).thenApply((i) -> Integer.toString(i)).thenAccept(System.out::println);
异常处理:
package com.ecut.completablefuture; import java.util.concurrent.CompletableFuture; public class ExceptionTest {
private static Integer Div(Integer para){
return para / 0 ;
} public static void main(String[] args) {
CompletableFuture<Integer> completeFuture = CompletableFuture.supplyAsync(()->Div(1)).exceptionally(ex ->{
System.out.println(ex.toString());
return 0;
});
}
}
源码地址:
https://github.com/SaberZheng/concurrent-test
转载请于明显处标明出处:
https://www.cnblogs.com/AmyZheng/p/10486212.html
《实战Java高并发程序设计》读书笔记六的更多相关文章
- 《实战java高并发程序设计》源码整理及读书笔记
日常啰嗦 不要被标题吓到,虽然书籍是<实战java高并发程序设计>,但是这篇文章不会讲高并发.线程安全.锁啊这些比较恼人的知识点,甚至都不会谈相关的技术,只是写一写本人的一点读书感受,顺便 ...
- 《实战Java高并发程序设计》读书笔记
文章目录 第二章 Java并行程序基础 2.1 线程的基本操作 2.1.1 线程中断 2.1.2 等待(wait)和通知(notify) 2.1.3 等待线程结束(join)和谦让(yield) 2. ...
- 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
- 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
- 【实战Java高并发程序设计 5】让普通变量也享受原子操作
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
- 【实战Java高并发程序设计 4】数组也能无锁:AtomicIntegerArray
除了提供基本数据类型外,JDK还为我们准备了数组等复合结构.当前可用的原子数组有:AtomicIntegerArray.AtomicLongArray和AtomicReferenceArray,分别表 ...
- 【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference AtomicReference无法解决上述问题的根 ...
- 【实战Java高并发程序设计 1】Java中的指针:Unsafe类
是<实战Java高并发程序设计>第4章的几点. 如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现.现在,就让我 ...
- 《实战Java高并发程序设计》读书笔记三
第三章 JDK并发包 1.同步控制 重入锁:重入锁使用java.util.concurrent.locks.ReentrantLock类来实现,这种锁可以反复使用所以叫重入锁. 重入锁和synchro ...
- 《实战Java高并发程序设计》读书笔记二
第二章 Java并行程序基础 1.线程的基本操作 线程:进程是线程的容器,线程是轻量级进程,是程序执行的最小单位,使用多线程而不用多进程去进行并发程序设计是因为线程间的切换和调度的成本远远的小于进程 ...
随机推荐
- 深度优先搜索 DFS(Depath First Search, DFS)
深度优先搜索是一种枚举所有完整路径以遍历所有情况的搜索方法.(不撞南墙不回头) DFS一般用递归来实现,其伪代码思路过程一般如下: void DFS(必要的参数){ if (符和遍历到一条完整路 ...
- java简单学生成绩管理系统
题目要求: 一. 数据结构要求:(5 分) 1.定义 ScoreInformation 类,其中包括七个私有变量(stunumber, name, mathematicsscore, englishi ...
- style.display = "inline或inline";和style.display = "";的区别
function a(){ if($('#b').attr('checked')){ $('.c').css("display",""); //"di ...
- C#中向ListView控件中添加一行数据
C#中向ListView控件中添加一行数据: ,先声明一个ListViewItem: ListViewItem item = new ListViewItem(); ,添加第一列数据: item.Te ...
- 关于RTP时间戳及多媒体通信同步的问题(转)
文章转载自:罗索实验室 [http://www.rosoo.net/a/201101/10776.html]
- 215. 数组中的第K个最大元素(TOP-K问题)
问题: 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2输出 ...
- css 单位之px , em , rem
px : Pixel像素单位.像素是相对显示器分辨率而言.em : 相对长度单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px).rem : 相对单 ...
- spring(六):事务
事务特性ACID 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做: 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行 ...
- python logging 总结
基本用法: import sys # 获取logger实例,如果参数为空则返回root logger logger = logging.getLogger("AppName" ...
- Python | 面向对象中的名词总结
一.变量名称 (最前的序号表示将来用到的频繁程度) 5 全局变量: 1. 文件中出现的变量,不归属于函数及类:2.在函数用用global声明的变量 2 局部变量: 1.类的方法中没有self.,只能在 ...