第六章 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;
});
}
}

6、StampedLock

源码地址:

https://github.com/SaberZheng/concurrent-test

转载请于明显处标明出处:

https://www.cnblogs.com/AmyZheng/p/10486212.html

《实战Java高并发程序设计》读书笔记六的更多相关文章

  1. 《实战java高并发程序设计》源码整理及读书笔记

    日常啰嗦 不要被标题吓到,虽然书籍是<实战java高并发程序设计>,但是这篇文章不会讲高并发.线程安全.锁啊这些比较恼人的知识点,甚至都不会谈相关的技术,只是写一写本人的一点读书感受,顺便 ...

  2. 《实战Java高并发程序设计》读书笔记

    文章目录 第二章 Java并行程序基础 2.1 线程的基本操作 2.1.1 线程中断 2.1.2 等待(wait)和通知(notify) 2.1.3 等待线程结束(join)和谦让(yield) 2. ...

  3. 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  4. 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  5. 【实战Java高并发程序设计 5】让普通变量也享受原子操作

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  6. 【实战Java高并发程序设计 4】数组也能无锁:AtomicIntegerArray

    除了提供基本数据类型外,JDK还为我们准备了数组等复合结构.当前可用的原子数组有:AtomicIntegerArray.AtomicLongArray和AtomicReferenceArray,分别表 ...

  7. 【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference AtomicReference无法解决上述问题的根 ...

  8. 【实战Java高并发程序设计 1】Java中的指针:Unsafe类

    是<实战Java高并发程序设计>第4章的几点. 如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现.现在,就让我 ...

  9. 《实战Java高并发程序设计》读书笔记三

    第三章 JDK并发包 1.同步控制 重入锁:重入锁使用java.util.concurrent.locks.ReentrantLock类来实现,这种锁可以反复使用所以叫重入锁. 重入锁和synchro ...

  10. 《实战Java高并发程序设计》读书笔记二

    第二章  Java并行程序基础 1.线程的基本操作 线程:进程是线程的容器,线程是轻量级进程,是程序执行的最小单位,使用多线程而不用多进程去进行并发程序设计是因为线程间的切换和调度的成本远远的小于进程 ...

随机推荐

  1. MySQL | 查看log日志

    1. 进入mysql mysql -u用户名 -p密码 2. 开启日志 et global general_log=on: 3. 查看mysql日志文件的路径 show variables like ...

  2. Python2安装MySQLdb

    在http://www.lfd.uci.edu/~gohlke/pythonlibs/#mysql-python下载对应的包版本,如果是win7 64位2.7版本的python,就下载 MySQL_p ...

  3. 题解 洛谷 P4145 【上帝造题的七分钟2 / 花神游历各国】

    题目 上帝造题的七分钟2 / 花神游历各国 题目背景 XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. 题目描述 "第一分钟,X说,要有数列,于是便给定了一个正整数数列. ...

  4. SDRAM中数据掩码的作用

    DQM就是掩码控制位.在sdram中,每个DQM控制8bit Data在读操作的时候没什么大的影响,比如你读32位的sdram module, 但你只要其中低8bit的数据,没有关系,只要读出32bi ...

  5. Openstack 简单梳理,(自用 慎点)

    这个图里面的彩色方块,就是OpenStack最核心的组件. 推荐几个大咖,大家可以百度找他们的博客来看:陈沙克.何明桂.孔令贤,Cloudman.

  6. python使用libnum,gmpy2快速解RSA

    直接贴出Pcat师傅的解题脚本 # -*- coding:utf8 -*- __author__='pcat@chamd5.org' import libnum import gmpy2 n=7306 ...

  7. 解决VS2013报错fopen、sprintf等函数安全的问题

    VS2013中使用fopen.sprintf等函数是会出现安全问题: error C4996: 'fopen': This function or variable may be unsafe. Co ...

  8. 概念理解_L2范数(欧几里得范数)

    L1范数 L1范数是指向量中各个元素绝对值之和 L2范数 L2范数.欧几里得范数一些概念. 首先,明确一点,常用到的几个概念,含义相同. 欧几里得范数(Euclidean norm) ==欧式长度 = ...

  9. 常见css属性

    div {            width: 100px;            height: 100px;            /* 表示行高 */            line-heigh ...

  10. Android开发实战——记账本(3)

    开发日志(3)——适配器 昨天将bean类还有DatabaseHelper类写完.为了在MainActivity中调用,将数据保存到数据库中并显示出来.所以要先编写适配器CostListAdapter ...