第六章 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. c语言修炼之一

    1.C项目要高内聚(模块功能必须明确,一个模块完成一个功能).低耦合(接口尽可能简单,减少各模块间的联系). 2.register类型不能为模块间的全局变量.模块内的全局变量.局部static变量.( ...

  2. 用eclipse中自带的jetty启动项目

    1.建立datasources.xml,创建jndi <jee:jndi-lookup id="datasource" jndi-name="jndiname&qu ...

  3. can总线中什么是远程帧

    所谓“远程帧”是一个传统翻译上的误区.Remote Frame实际上它的意义是“遥控帧”,发起方发起特定ID的远程帧,并且只发送ID部分,那么与其ID相符的终端设备就有义务在后半段的数据部分接管总线控 ...

  4. python之路之网络基础

    c类地址

  5. ZooKeeper Distributed lock

    https://segmentfault.com/a/1190000016351095 http://www.dengshenyu.com/java/%E5%88%86%E5%B8%83%E5%BC% ...

  6. Codeforces Round #598 (Div. 3) B Minimize the Permutation

    B. Minimize the Permutation You are given a permutation of length nn. Recall that the permutation is ...

  7. Django初步皮毛

    Django是一个用python编写的Web框架. #Django安装 pip install Django 然后是配置环境变量,将这目录添加到系统环境变量中: C:\Python33\Lib\sit ...

  8. Apache Kafka(八)- Kafka Delivery Semantics for Consumers

    Kafka Delivery Semantics 在Kafka Consumer中,有3种delivery semantics,分别为:至多一次(at most once).至少一次(at least ...

  9. bootstrap联动校验(转载)

    接触bootstrapvalidator时间不久,最近需要多个字段共同验证,网上查了一下未找到,查阅api文档,发现确实可以实现. 先看dom <div class="form-gro ...

  10. Java替换字符串中的\r\n

    public static void main(String[] args) { String str = "啊\r\n啊"; str = str.replaceAll(" ...