JUC学习笔记五:四大函数式接口和流Stream; ForkJoinPool

一、四大函数式接口和Stream

四大函数式接口:

函数式接口是java8的新特性之一:它封装好了四种不同功能的函数式接口。都位于java.util.function包下。可以从接口的名字来记忆接口有无返回值,有无参数等等。下面表格是具体介绍:

在这里插入图片描述

  • 消费型Consumer:输入一个参数,这个参数被消费了,无返回值:有参数,无返回值。
  • 供给型Supplier:没有输入参数,但是程序供给出来了返回值:无参数,有返回值。
  • 函数型接口Function:函数是有输入有输出的。所以有参数,有返回值。
  • 断定型接口Predicate:给程序一个参数,程序用这个参数断言是否符合某条件:有参数,返回值为boolean类型。

下面分别举例四种接口的使用。

public class FunctionalInterfaceDemo{
	public static void main(String[] args){
 		//函数型接口(泛型左边为入参,右边为返回类型)
        Function<String, Integer> function = s -> s.length();//有一个输入,有一个输出
        System.out.println(function.apply("Younjzxx"));

        //断定型接口,输入任何类型,输出的是对于这个输入参数的某种逻辑判断,true或者false
        Predicate<String> predicate = s -> s.equals("abc");
        System.out.println(predicate.test("abc"));

        //消费型接口,输入某个参数,用这个参数做某个业务,无返回值
        Consumer<String> consumer = s -> System.out.println(s);
        consumer.accept("print me ~");

        //供给型接口,无参数,有返回值。
        Supplier<String> supplier = () -> {
            return "供给型接口";
        };
        System.out.println(supplier.get());
	}
}

输出:

8
true
print me ~
供给型接口

流Stream:

流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
其实就是将集合或者数组的每一个元素分离开,形成一条一条“流”的形式,用这些流进行各种集合中元素的操作。

Stream流的特点:
1.Stream 自己不会存储元素
2.Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
3.Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

使用方法:
1.创建一个Stream:一个数据源(数组、集合)
2.中间操作:一个中间操作,处理数据源数据
3.终止操作:一个终止操作,执行中间操作链,产生结果

下面我们创建一个数组的list,然后用这个list来进行流式编程。list内存储的是自定义的User对象,User定义如下:

@Data
@NoArgsConstructor
@AllArgsConstructor
class User
{
    private Integer id;
    private String  userName;
    private int     age;
}

我们创建一个含有5个User对象的list:

		User u1 = new User(11, "a", 23);
        User u2 = new User(12, "b", 24);
        User u3 = new User(13, "c", 22);
        User u4 = new User(14, "d", 28);
        User u5 = new User(16, "e", 26);

        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);

我们要得到的结果是:输出偶数id,年龄大于24,用户名显示为大写且用户名字母倒排序。只输出排序后第一个用户的用户名。
用Stream可以方便的完成这个需求:

list.stream().filter(u -> u.getId() % 2 == 0).filter(u -> u.getAge() > 24).
                map(m -> {
                    return m.getUserName().toUpperCase();
                }).sorted((s1, s2) -> -s1.compareTo(s2)).limit(1).forEach(System.out::println);//sout : E

二、ForkJoin分支合并框架

概念:

Fork:把一个复杂任务进行分拆,大事化小
Join:把分拆任务的结果进行合并

扫描二维码关注公众号,回复: 9272046 查看本文章

ForkJoinPool:分支合并池,可以类比线程池
在这里插入图片描述

ForkJoinTask 类比=> FutureTask
在这里插入图片描述

RecursiveTask:递归任务,继承了ForkJoinTask,一般直接继承RecursiveTask即可。
继承后可以实现递归(自己调自己)调用的任务:

举例:

例子:使用ForkJoin实现从a到b的所有整数的和:

public class ForkJoinDemo {
    public static void main(String[] args) throws Exception {
        MyTask myTask = new MyTask(50, 100);
        ForkJoinPool threadPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = threadPool.submit(myTask);
        System.out.println(forkJoinTask.get());//输出结果3825
        threadPool.shutdown();
    }
}

//直接继承RecursiveTask<>抽象类,它继承了ForkJoinTask<>抽象类
class MyTask extends RecursiveTask<Integer> {
    //10以内不用拆分
    private static final Integer ADJUST_VALUE = 10;
    private int begin;
    private int end;
    private int result;

    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if((end - begin) <= ADJUST_VALUE){
            //end和begin相差不到10,不需要forkJoin
            for(int i = begin; i <= end; i++){
                result = result + i;
            }
        }else{
            int middle = (begin + end)/2;
            //任务1
            MyTask task01 = new MyTask(begin,middle);
            //任务2
            MyTask task02 = new MyTask(middle+1,end);
            //递归地分任务
            task01.fork();
            task02.fork();
            result =  task01.join() + task02.join();
        }

        return result;
    }
}
发布了16 篇原创文章 · 获赞 2 · 访问量 447

猜你喜欢

转载自blog.csdn.net/qq_31314141/article/details/104216466
今日推荐