《实战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.线程的基本操作 线程:进程是线程的容器,线程是轻量级进程,是程序执行的最小单位,使用多线程而不用多进程去进行并发程序设计是因为线程间的切换和调度的成本远远的小于进程 ...
随机推荐
- V8 是怎么跑起来的 —— V8 中的对象表示
V8 是怎么跑起来的 —— V8 中的对象表示 ThornWu The best is yet to come 30 人赞同了该文章 本文创作于 2019-04-30,2019-12-20 迁移至此本 ...
- 杭电oj————2057(java)
question:A+ B again 思路:额,没啥思路/捂脸,用java的long包里的方法,很简单,只是有几次WA,有几点要注意一下 注意:如果数字有加号要删除掉,这里用到了正则表达式“\\+” ...
- Linux - Shell - 参数获取
概述 参数 背景 复习一下 shell 脚本的参数获取 场景 os centos7 1. 参数: 基础 概述 简单描述 参数 1. 获取参数 获取 第一个 参数 获取参数 使用 ${num} 获取参数 ...
- LED Holiday Light -Picking LED Christmas Lights, 4 Things
LED Christmas lights are not very cheap, but you should know that LED lights can be used for more th ...
- 转载:android audio policy
Audio policy basic:https://www.cnblogs.com/CoderTian/p/5705742.html Set volume flow:https://blog.csd ...
- [LOJ113] 最大异或和 - 线性基
虽然是SB模板但还真是第一次手工(然而居然又被运算符优先级调戏了) #include <bits/stdc++.h> using namespace std; #define int lo ...
- Dimension reduction
materials: 1. Dimension Reduction - IsoMap
- Tp5整理
一.命名规则 目录级和文件命名 目录采用小写字母+下划线命名: 类文件名采用驼峰法命名(比如:ArticleDetail.php),其它文件与目录命名规则同: 类名与类文件名须保持一致,采用驼峰法: ...
- 终极教程【zhong】
just for a better future! 资源教程 aiim 综合类 前端知识体系 前端知识结构 Web前端开发大系概览 We ...
- Python生成通用唯一识别码UUID
from uuid import uuid4 for i in range(100): uid = str(uuid4()) suid = ''.join(uid.split('-')) print( ...