一、四大函数式接口和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:把分拆任务的结果进行合并
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;
}
}