四大函数式接口(必须掌握)
函数式接口:只有一个方法的接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
//简化编程模型,在新版本的框架底层大量应用
//foreach(消费者的函数式接口)
Function接口(函数型接口)
/**
* Function 函数型接口,有一个输入参数,有一个输出
* 只要是函数型接口,可以用lambda表达式简化
*/
public class demo01 {
public static void main(String[] args) {
// Function<String,String> function=new Function<String,String>(){
// @Override
// public String apply(String o) {
// return o;
// }
// };
Function<String,String> function=(str)->{
return str;
};
System.out.println(function.apply("asd"));
}
}
Preddicate接口(断定型接口)
/**
* 断定型接口: 有一个输入参数,返回值只能是布尔值!
*/
public class Demo02 {
public static void main(String[] args) {
// Predicate<String> predicate=new Predicate<String>() {
// @Override
// public boolean test(String o) {
// if(o.isEmpty())
// {
// return true;
// }
// return false;
// }
// };
Predicate<String> predicate=(str)->{
return str.isEmpty();
};
System.out.println(predicate.test("123"));
}
}
Consumer消费型接口
/**
* Consumer 消费型接口:只有输入,没有返回值
*/
public class demo03 {
public static void main(String[] args) {
// Consumer<String> consumer = new Consumer<String>(){
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// };
Consumer<String> consumer=(s)->{
System.out.println(s);
};
consumer.accept("yhy");
}
}
Supplier供给型接口
/**
* Suppiler 没有参数,只有返回值
*/
public class demo04 {
public static void main(String[] args) {
// Supplier supplier=new Supplier<String>() {
// @Override
// public String get() {
// return "114514";
// }
// };
Supplier supplier=()->{
return "114514";
};
System.out.println(supplier.get());
}
}
Stream流式计算
集合,MySQL本质都是存储东西。计算交给流来操作。
在这个接口有如下方法
等等这些方法都是函数式接口。
public class Test {
public static void main(String[] args) {
User u1=new User(1,"a",21);
User u2=new User(2,"b",22);
User u3=new User(3,"c",23);
User u4=new User(4,"d",24);
User u5=new User(5,"e",25);
User u6=new User(6,"g",26);
//集合存储
List<User> list= Arrays.asList(u1,u2,u3,u4,u5,u6);
//计算交给Stream流
//Lambda表达式、链式编程、函数式接口、Stream流式计算
list.stream()
.filter(u->{return u.getId()%2==0;})
.filter(u->{return u.getAge()>23;})
.map(u->{return u.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
Forkjoin(分支合并)
在jdk1.7,并行执行任务!提高效率。大数据量!
大数据:Map Reduce(把大任务拆分为小任务)
Forkjoin特点:工作窃取
里面维护的都是双端队列。
两个线程执行任务,一个提前完成了就会去执行另一个的任务。
/**
* 求和计算任务
* 3000 6000(forkjoin) 9000(Stream并行流)
* //如何使用Forkjoin
* //1.forkjoinpool
* //2.计算任务forkjointaskPool.execute(ForkJoinTask<?>task)
* //3.计算类继承RecursiveTask<Long>
*/
public class ForkJoin extends RecursiveTask<Long> {
private Long start;
private Long end;
private Long temp=10000L;
public ForkJoin(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if((end-start)<temp) {
Long sum = 0L;
for(int i=0;i<10_0000_0000;i++)
{
sum+=i;
}
return sum;
}else{
//分支合并计算
Long middle=(start+end)/2;//中间值
ForkJoin task1=new ForkJoin(start,middle);
task1.fork();//拆分任务,将任务压入线程队列。
ForkJoin task2=new ForkJoin(middle+1,end);
task2.fork();//拆分任务,将任务压入线程队列。
return task1.join()+task2.join();
}
}
}
这个玩意本质上就是的二分+递归,很简单的算法。
每二分一次线程数+1;各个线程执行不同段的计算任务。
/**
* 3000 6000(forkjoin) 9000(Stream并行流)
*/
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// test1(); //sum-243309312时间:9346
// test2(); //8088?????? 好像也没快多少
test3(); //700 究极快,最大限度利用CPU
}
public static void test1(){
long start =System.currentTimeMillis();
Long sum=0L;
for(Long i=1L;i<=10_0000_0000;i++){
sum+=i;
}
long end=System.currentTimeMillis();
System.out.println("sum"+sum+"时间:"+(end-start));
}
//使用forkjoin
public static void test2() throws ExecutionException, InterruptedException {
long start =System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> forkJoin = new ForkJoin(0L, 10_0000_0000L);
ForkJoinTask<Long> submit=forkJoinPool.submit(forkJoin);//提交任务,有结果
Long sum=submit.get();
//forkJoinPool.execute(forkJoin);//执行,没有结果
long end=System.currentTimeMillis();
System.out.println("sum"+sum+"时间:"+(end-start));
}
//使用stream并行流
public static void test3(){
long start =System.currentTimeMillis();
//(]
LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0,Long::sum);
long end=System.currentTimeMillis();
System.out.println("sum"+"时间:"+(end-start));
}
}
异步回调(Future接口)
Future接口设计的初衷:对将来的事件进行建模。
前后端异步通信有ajax,java中也有异步通信。
/**
* 异步调用: CompltableFuture
* //异步调用
* //成功回调
* //失败回调
*/
public class demo01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// //没有返回值的异步回调
// CompletableFuture<Void> completedFuture = CompletableFuture.runAsync(()->{
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// System.out.println(Thread.currentThread().getName()+"runAsync=>void");
// });
// System.out.println("11111");
// completedFuture.get(); //阻塞获取执行结果
// System.out.println("22222");
//有返回值的异步回调
//ajax,成功和失败的回调
//返回的是错误信息
CompletableFuture<Integer> completedFuture =CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" runAsync=>void");
int t=10/0;
return 1024;
});
System.out.println(completedFuture.whenComplete((t, u) -> {
System.out.println("t=>"+t); //正常的返回结果
System.out.println("u=>"+u); //抛出的错误信息
}).exceptionally((e) -> {
System.out.println(e.getMessage());//获取报错信息
return 233; //获取到错误的返回结果
}).get());
}
}
-
whenComplete(...)
方法在CompletableFuture正常完成或遇到异常时均能执行。它接收两个参数,第一个参数是正常返回的结果(如果有),第二个参数是抛出的异常(如果有)。所以,这个方法中的输出语句会在CompletableFuture正常完成或遇到异常时都执行。 -
exceptionally(...)
方法是用于处理异常情况的。如果CompletableFuture遇到异常,exceptionally(...)
方法会被触发,并且它返回一个备用的结果。在你的代码中,exceptionally(...)
方法中的代码会捕获到supplyAsync(...)
中的异常(因为你在supplyAsync(...)
中除以0了),然后输出异常信息并返回一个备用的结果(233)。因此,这个方法会执行,并输出异常信息。
综上所述,这句输出语句会执行是因为whenComplete(...)
方法在正常或异常完成时都会执行,而exceptionally(...)
方法会捕获异常并处理它,然后返回备用结果。