Java并发编程学习篇4_四大函数式接口、Stream流式计算、ForkJoin分支合并、Future异步回调

  • 四大函数式接口

    1. Function函数式接口-有参、有返回值
    2. Predicate断定型接口-有参、返回布尔值
    3. Consumer消费者接口-有参、无返回值
    4. Supplier生产者接口-无参、有返回值
  • Stream流式计算

  • ForkJoin分支合并

  • Future异步回调

一、四大函数式接口

简化编码技术: Lambda表达式、链式编程、函数式接口、Stream流式计算。

只要是函数式接口,就可以使用Lambda表达式简化

函数式接口:只有一个方法的接口,如 Runnable接口、forEach的参数是一个消费者类型的函数式接口

java.util.Function 包下的 有基本的四大函数式接口

  • Function
  • Consumer
  • Predicate
  • Supplier
========== Runnable 接口==========
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
========== foreach的 consumer 参数也是函数式接口 ===========
@Override
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}
=========== Consumer 消费者接口 =============
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

复制代码
1.Function函数式接口

说明

  • apply方法接受一个参数t,返回一个参数R
  • 可以使用Lambda表达式简化

源码

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t); ======》 接受一个参数 t 返回 R

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

复制代码

举例

package study_function;

import java.util.function.Function;


/**
 * Function函数式接口
 */
public class Demo1 {

    public static void main(String[] args) {
        // 一般形式
        Function function = new Function<String,String>() {
            @Override
            public String apply(String str) {
                return str;
            }
        };

        // 使用Lambda 简化
        Function function1 = (str)->{ return str;};
        Function function2 = str-> {return str;};

        System.out.println(function.apply("xiaosi")); // 输出 xiaosi
        System.out.println(function1.apply("xiaosi")); // 输出 xiaosi
        System.out.println(function2.apply("xiaosi")); // 输出 xiaosi

    }
}


复制代码
2.Predicate断定型接口

说明

  • 断定型接口
  • 接受一个参数,返回值是布尔型

源码

/**
 * Represents a predicate (boolean-valued function) of one argument.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #test(Object)}.
 *
 * @param <T> the type of the input to the predicate
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * Returns a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}.
     *
     * @param <T> the type of arguments to the predicate
     * @param targetRef the object reference with which to compare for equality,
     *               which may be {@code null}
     * @return a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}


复制代码

举例

package study_function;

import java.util.function.Predicate;


/**
 * Predicate 判定性接口
 */
public class Demo2_predicate {

    public static void main(String[] args) {
        // 一般方式
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {

                if(!s.isEmpty() && s.length() >= 3){
                    return true;
                }
                return false;
            }
        };

        // 使用lambda简化
        Predicate<String> predicate1 = (s)->{
            if((!s.isEmpty()) && (s.length() >= 3)) {
                return true;
            }
            return false;
        };

        System.out.println(predicate.test("xiaosi")); // true
        System.out.println(predicate1.test("xiaosi")); // true
    }
}


复制代码
3.Consumer消费者接口

说明

  • 接受一个参数,无返回值

源码

/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}


复制代码

举例

package study_function;

import java.util.function.Consumer;


/**
 * Consumer 消费者接口
 */
public class Demo3_consumer {
    public static void main(String[] args) {
        // 一般方式生产一个字符串
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("消费了====》 " + s);

            }
        };

        // 使用Lambda表达式简化
        Consumer<String> consumer1 = (str)->{
            System.out.println("消费了===》" + str);
        };

        consumer.accept("xiaosi"); // 消费了====》 xiaosi
        consumer1.accept("si");// 消费了====》 si
    }
}


复制代码
4.Supplier生产者接口

说明

  • 无输入参数,有返回值

源码

package java.util.function;

/**
 * Represents a supplier of results.
 *
 * <p>There is no requirement that a new or distinct result be returned each
 * time the supplier is invoked.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #get()}.
 *
 * @param <T> the type of results supplied by this supplier
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

复制代码

二、Stream流式计算

什么是Stream流式计算

  • 常用的集合是为了存储数集,而对于集合数据的一些处理(像筛选集合数据等)可以使用Stream流来处理
  • java.util.tream包下的Stream接口 支持顺序和并行聚合操作的一系列元素
  • Stream流可以结合四大函数式接口进行数据处理(方法的参数支持函数式接口)

使用

  • 集合.stream() 可以将集合对象 转为 流对象,调用流对象的一些方法进行数据操作
  • 常用方法

filter(Predicate<? super T> predicate) 返回由与此给定谓词匹配的此流的元素组成的流。

  • count() 返回此流中的元素数。
  • forEach(Consumer<? super T> action) 对此流的每个元素执行操作。
  • sorted(Comparator<? super T> comparator) 返回由该流的元素组成的流,根据提供的 Comparator进行排序。
  • map(Function<? super T,? extends R> mapper)返回由给定函数应用于此流的元素的结果组成的流。
  • sorted(Comparator<? super T> comparator)返回由该流的元素组成的流,根据提供的 Comparator进行排序。

举例

package study_stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Demo1 {
    public static void main(String[] args) {

        User user1 = new User("xiaosi1",20,18000);
        User user2 = new User("xiaosi2",21,19000);
        User user3 = new User("xiaosi3",23,20000);
        User user4 = new User("xiaosi4",24,21000);
        User user5 = new User("xiaosi5",25,22000);
        User user6 = new User("xiaosi6",26,23000);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5,user6);

        // 1. forEach

        list.stream().forEach((user)->{
            System.out.println(user);

        });

        list.stream().close();

        System.out.println("===================");


        //2.  filter、Predicate判定式函数接口
        // 筛选年龄在21之上,薪水在20000以上的user

        list.stream().
                filter((user)->{ return user.getSalary() > 20000; }).
                filter((user)->{return user.getAge()>= 21; }).
                forEach(System.out::println);


        list.stream().close();

        System.out.println("==================");

        // 3. map(Function<? super T,? extends R> mapper)
        //返回由给定函数应用于此流的元素的结果组成的流。
        // salary排序

        list.stream().
                filter((user)->{return user.getSalary() < 20000; }).
                map((user)->{ return user.getSalary() + 2000; }). // 返回salary,18000 + 2000 、19000 + 2000
                sorted((u1,u2)->{ return u1.compareTo(u1); }).
                forEach(System.out::println);


        list.stream().close();

    }




}



class User{
    private String name;
    private int age;
    private int salary;

    public User(String name, int age, int salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
}

输出:

User{name='xiaosi1', age=20, salary=18000}
User{name='xiaosi2', age=21, salary=19000}
User{name='xiaosi3', age=23, salary=20000}
User{name='xiaosi4', age=24, salary=21000}
User{name='xiaosi5', age=25, salary=22000}
User{name='xiaosi6', age=26, salary=23000}
===================
User{name='xiaosi4', age=24, salary=21000}
User{name='xiaosi5', age=25, salary=22000}
User{name='xiaosi6', age=26, salary=23000}
==================
20000
21000



复制代码

三、ForkJoin分支合并

概念

  • 通过FokeJoinPool实例调用方法

    • void execute(ForkJoinTask<?> task) 为异步执行给定任务的排列。
    • void execute(Runnable task) 在将来的某个时间执行给定的命令。
    • T submit(ForkJoinTask task) 提交一个ForkJoinTask来执行。返回当前任务,在调用get()方法拿到返回值
  • 执行任务的方法参数为ForkJoinTask,实现子类有

    • RecursiveAction 递归事件,无返回值
    • RecursiveTask 递归任务,有返回值
  • MyTask继承ForkJoinTask<返回值>,重写 compute计算方法

  • 最后执行

    • ForkJoinPool forkJoinPool = new ForkJoinPool();
    • ForkJoinTask res = forkJoinPool.submit(myTask);
    • System.out.println(res.get());

    举例



============ MyRecursiveTask ========
package study_fokejoin;

import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;


/**
 * 计算 1 - 10_0000_0000的累和
 * 使用分支合并
 */
public class MyRecursiveTask extends RecursiveTask<Long> {

    private Long start = 1L;
    private Long end;

    // 临界值,判断选择分支合并 还是 一般方法
    private Long temp = 10000L;

    long sum = 0L;

    public MyRecursiveTask(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    // 分支合并计算方法
    @Override
    protected Long compute() {
        // 一般方法
        if((end - start) < temp){

            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } // ForkJoin方法
        else{

            long mid = (start + end) /2;


            // 拆分任务,将任务压入线程队列

            MyRecursiveTask task1 = new MyRecursiveTask(start,mid);
            task1.fork();

            MyRecursiveTask task2 = new MyRecursiveTask(mid+1,end);
            task2.fork();


            // 合并子任务结果
            long sum = task1.join() + task2.join();
            return sum;
        }

    }
}

============ Test ===============
package study_fokejoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 使用FokrJoin计算
        MyRecursiveTask task  = new MyRecursiveTask(1L,10_0000_0000L);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> res = forkJoinPool.submit(task);
        System.out.println(res.get());

        // 使用并行Stream流
        System.out.println(LongStream.rangeClosed(1L, 10_0000_0000L).parallel().reduce(0, Long::sum));
    }
}



复制代码

四、异步回调

概念

  • 类似ajax技术,可以进行异步执行、成功回调、失败回调。
  • java.util.concurrent包下的 接口Future,有
    • 实现子类:CompletableFuture , CountedCompleter , ForkJoinTask , FutureTask , RecursiveAction , RecursiveTask , SwingWorker
  • CompletableFuture 有静态方法
    • 无返回结果

image.png

  • 有返回结果

image.png 举例

package study_future;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class Demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        test2();

    }

    // 1. 无返回值的 异步
    static void  test1() throws ExecutionException, InterruptedException {
        CompletableFuture<Void>  completableFuture =  CompletableFuture.runAsync(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("异步任务执行了!!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        });

        System.out.println("xiaosi1");
        completableFuture.get();


    }

    // 2. 有返回值的 异步
    static void  test2() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer>  completableFuture =  CompletableFuture.supplyAsync(()->{
            int num = 10 / 0;
            try {


                TimeUnit.SECONDS.sleep(3);
                return 1;


            } catch (Exception e) {
                e.printStackTrace();
                return -1;
            }
        });


        System.out.println("xiaosi2");

        completableFuture.whenCompleteAsync((t,u)->{
            System.out.println(t+"=====> " + t); // 成功的时候返回值
            System.out.println(u+"=====> " + u); // 失败的信息
            System.out.println("有返回值的异步执行了!");

        }).exceptionally((e)->{ // 异常捕获
            e.printStackTrace();
            return 404;
        }).get();



    }
}


复制代码

Supongo que te gusta

Origin juejin.im/post/7067049645574193159
Recomendado
Clasificación