《实战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;
        });
    }
}

 6、StampedLock

源码地址:

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

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

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

posted @ 2019-03-07 19:13  AmyZheng  阅读(277)  评论(0编辑  收藏  举报