欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JAVA8给我带了什么——Optional和CompletableFuture

程序员文章站 2023-08-18 18:12:52
不管是JAVA,还是.NET。我们常常会看到空异常(NullPointerException)。这种异常都是在运行的过程中出现。往往是变量是一个null值。但是你引用这个变量的后继字段或是方法。所以我们代码里面常常会出现if (变量!=null)的相关操作。如果你是一个.NET开发人员的话,那么你一 ......

不管是java,还是.net。我们常常会看到空异常(nullpointerexception)。这种异常都是在运行的过程中出现。往往是变量是一个null值。但是你引用这个变量的后继字段或是方法。所以我们代码里面常常会出现if (变量!=null)的相关操作。
如果你是一个.net开发人员的话,那么你一定知道.net的可以为空的数据类型。同样子java8引入了一个optional类型,目地是为了决解为空带来的一系列问题。optional类提供了俩个静态的方法

  • of方法:创建一个非空的optional类型。
  • ofnullable方法:创建一个可以为空的optional类型。

让我们一起看一下用法吧。

 1 package com.aomi;
 2 
 3 import java.util.hashmap;
 4 import java.util.map;
 5 import java.util.optional;
 6 
 7 public class main {
 8     private static map<string, string> maps = new hashmap<string, string>();
 9 
10     public static void main(string[] args) {
11         // todo auto-generated method stub
12 
13         maps.put("aomi", "val1");
14         maps.put("key1", "val2");
15 
16         string val  = getvalue("aaa");
17         
18         optional<string> optionalval = optional.ofnullable(val);
19         
20         if(optionalval.ispresent())
21         {
22             system.out.println(val.replace("a", "b"));
23         }
24         else
25         {
26             system.out.println("拿到变量值为空");
27         }
28     }
29 
30     public static string getvalue(string key) {
31         if (maps.containskey(key))
32             return maps.get(key);
33         return null;
34     }
35 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

ispresent方法用于判断当前的变量是否为空。从某意义上来讲笔者觉得这好像并没有多大的好处。同样子我们要用ispresent来判断是否为空。那么跟写if(变量!=null)有什么分别。所以笔者打算换一换。

 1 package com.aomi;
 2 
 3 import java.util.hashmap;
 4 import java.util.map;
 5 import java.util.optional;
 6 
 7 public class main {
 8     private static map<string, string> maps = new hashmap<string, string>();
 9 
10     public static void main(string[] args) {
11         // todo auto-generated method stub
12 
13         maps.put("aomi", "val1");
14         maps.put("key1", "val2");
15 
16         string notnullval  = getvalue("aomi");
17         string nullval  = getvalue("aaa");
18         
19         optional<string> optnotnullval = optional.ofnullable(notnullval);
20         optional<string> optnullval = optional.ofnullable(nullval);
21         
22         system.out.println(optnotnullval.orelse("拿到变量值为空"));
23         system.out.println(optnullval.orelse("拿到变量值为空"));
24     }
25 
26     public static string getvalue(string key) {
27         if (maps.containskey(key))
28             return maps.get(key);
29         return null;
30     }
31 }

上面的代码是这样子的。笔者拿俩个变量,一个变量是为空的。一个不为空。然后笔者用optional类的orelse来做文章。显示如下。

JAVA8给我带了什么——Optional和CompletableFuture

当然optional类里面提供了几个用于获得值的方法。

  • get方法:就是用于获得值,如果当前的optional类是一个有值的变量,那么就返回值。如果没有的话,不好意思!他会报错。
  • orelse方法:表示如果为空的话,我就返回方法给定的值。否则返回当前的值。
  • orelseget方法:表示如果为空的话,执行一个回调的方法函数。你可以传入一个lambda表达。
  • orelsethrow方法:表示如果为空的话,回返一个异常,可以是一个自定义的异常。

以上这些方法,笔者认为并不能说明optional类的特别之处。如下

 1 package com.aomi;
 2 
 3 import java.util.hashmap;
 4 import java.util.map;
 5 import java.util.optional;
 6 
 7 public class main {
 8     private static map<string, string> maps = new hashmap<string, string>();
 9 
10     public static void main(string[] args) {
11         // todo auto-generated method stub
12 
13         maps.put("aomi", "val1");
14         maps.put("key1", "val2");
15 
16         string notnullval = getvalue("aomi");
17     
18 
19         optional<string> optnotnullval = optional.ofnullable(notnullval);
20 
21         optional<string> optnullnewval = optnotnullval.map(ss -> ss.replace("a", "b"));
22 
23         system.out.println(optnullnewval.orelse("拿到变量值为空"));
24     }
25 
26     public static string getvalue(string key) {
27         if (maps.containskey(key))
28             return maps.get(key);
29         return null;
30     }
31 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

我们可以到optional类提供了一个map方法。这个功能跟以前讲到的流的map有一点类似。你们可以看到笔者在上面通过map方法来把'a'字符替换为‘b’。最后val1变成为vbl1。如果笔者还想把‘l‘替换为’r‘。后面在增加一个map如下

optional<string> optnullnewval = optnotnullval.map(ss -> ss.replace("a", "b")).map(ss->ss.replace("l","r"));

即然有map方法了。是不是也主是有filter方法。没有错。还真的有。如下。

 1 package com.aomi;
 2 
 3 import java.util.hashmap;
 4 import java.util.list;
 5 import java.util.map;
 6 import java.util.optional;
 7 
 8 public class main {
 9     private static map<string, string> maps = new hashmap<string, string>();
10 
11     public static void main(string[] args) {
12         // todo auto-generated method stub
13 
14         maps.put("aomi", "vbl1");
15         maps.put("key1", "val2");
16     
17         string notnullval = getvalue("aomi");
18 
19         optional<string> optnotnullval = optional.ofnullable(notnullval);
20 
21         optional<string> optnullnewval = optnotnullval.filter( ss->ss.contains("a")).map(ss->ss.replace("a", "b"));
22 
23         system.out.println(optnullnewval.orelse("拿到变量值为空"));
24     }
25 
26     public static string getvalue(string key) {
27         
28         if(maps.containskey(key))
29             return maps.get(key);
30         return "map";
31     }
32 }

笔者找出含有’a‘字符的字串符。然后"a"替换 "b"。主要修改代码俩个地方。如下

1.把val1修改为vbl1。主要是让他有值,却不含有'a'字符。了为证明他可以过滤掉有‘a’的字符串

maps.put("aomi", "vbl1");

2.增加filter方法进行过滤。条件必须含有'a'

.filter( ss->ss.contains("a"))

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

 

java为了空值的问题增加了optional类。提功能了一系列功能。大家可以试着用用感觉如何。

笔者记得好像是在java5的时候,java引一个future接口。如果你没有印像的话,那你们有没有用到过futuretask类呢。 以前要创建一个多线程的话,一般有俩种。一种是继承thread;一种是实现runnable

 1 package com.aomi;
 2 
 3 public class main {
 4 
 5     public static void main(string[] args) {
 6         // todo auto-generated method stub
 7 
 8         thread th1 = new thread() {
 9             @override
10             public void run() {
11                 system.out.println("这是一个thread副线程");
12             }
13         };
14         
15         th1.start();
16         
17         
18         thread th2 = new thread(new runnable() {
19             
20             @override
21             public void run() {
22                 system.out.println("这是一个runnable副线程");
23             }
24         });
25         
26         th2.start();
27         
28         try {
29             thread.sleep(2000);
30         } catch (interruptedexception e) {
31             // todo auto-generated catch block
32             e.printstacktrace();
33         }
34         
35         system.out.println("这是一个主线程");
36     }
37 
38 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

我们可以看到代码中的俩种方式了吧。这俩个方式都只有一个毛病。没有办法实现返回值的功能。所以引入了future接口。如下

 1 package com.aomi;
 2 
 3 import java.util.concurrent.callable;
 4 import java.util.concurrent.executionexception;
 5 import java.util.concurrent.futuretask;
 6 
 7 public class fmain {
 8     public static void main(string[] args) {
 9 
10         futuretask<string> task = new futuretask<>(new callable<string>() {
11             @override
12             public string call() throws exception {
13                 thread.sleep(1000);
14                 return "i am aomi";
15             }
16         });
17 
18         new thread(task).start();
19 
20         try {
21             system.out.println("主线程: 结果=" + task.get());
22         } catch (interruptedexception e) {
23             // todo auto-generated catch block
24             e.printstacktrace();
25         } catch (executionexception e) {
26             // todo auto-generated catch block
27             e.printstacktrace();
28         }
29 
30     }
31 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

我可以看到一个叫callable接口。是里面的call方法和runnable方法有一点像。只是一个有返回值,一个没有。futuretask类同时也提了很多方法。比如上的代码笔者在改改。加入判断是否取消了。如果没有取消的话,就取消掉他。然后也去获取他的值。

 1 package com.aomi;
 2 
 3 import java.util.concurrent.callable;
 4 import java.util.concurrent.executionexception;
 5 import java.util.concurrent.futuretask;
 6 
 7 public class fmain {
 8     public static void main(string[] args) {
 9 
10         futuretask<string> task = new futuretask<>(new callable<string>() {
11             @override
12             public string call() throws exception {
13                 thread.sleep(1000);
14                 system.out.println("副线程:返回值=i am aomi");
15                 return "i am aomi";
16             }
17         });
18 
19         new thread(task).start();
20 
21         try {
22             if (!task.iscancelled())
23             {
24                 task.cancel(true);
25                 system.out.println("取消副线程");
26                 system.out.println("主线程: 结果=" + task.get());
27             }
28             else
29             {
30                 system.out.println("主线程: 结果=" + task.get());
31             }
32                 
33         } catch (interruptedexception e) {
34             // todo auto-generated catch block
35             e.printstacktrace();
36         } catch (executionexception e) {
37             // todo auto-generated catch block
38             e.printstacktrace();
39         }
40 
41     }
42 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

看到了没有被取消了。同时你去获得取消线程的结果时,会发生异常。有没有.net的程序员,感觉像不像.net的任务(task)。 事实上有上面的功能大部业务都可以实现了。但是java8还是又引一个叫completablefuture类。相对于future接口增加了很多方法。如下获得异步里面的结果。

 1 package com.aomi;
 2 
 3 import java.util.concurrent.completablefuture;
 4 import java.util.concurrent.executionexception;
 5 
 6 public class cmain {
 7 
 8     public static void main(string[] args) {
 9         // todo auto-generated method stub
10         
11         completablefuture<string> future = new completablefuture<>();
12         
13         new thread(new runnable() {
14             
15             @override
16             public void run() {
17                 
18                 try {
19                     thread.sleep(2000);
20                 } catch (interruptedexception e) {
21                     // todo auto-generated catch block
22                     e.printstacktrace();
23                 }
24                 
25                 future.complete("i am a completablefuture");
26                 
27             }
28         }).start();
29         
30         
31         try {
32             
33             system.out.println(future.get());
34             
35         } catch (interruptedexception e) {
36             // todo auto-generated catch block
37             e.printstacktrace();
38         } catch (executionexception e) {
39             // todo auto-generated catch block
40             e.printstacktrace();
41         }
42 
43     }
44 
45 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

笔者在线程里面睡了2000秒。所以你们运行之个例子的时候,会发现慢了2秒才显示结果。说明future.get()会等线程的结果。事实上futuretask类也是一样子。所以completablefuture类提供一系列的功能组合。只要设计好的话,性能会提高很多。

 1 package com.aomi;
 2 
 3 import java.util.concurrent.completablefuture;
 4 import java.util.concurrent.executionexception;
 5 import java.util.concurrent.executor;
 6 import java.util.concurrent.executors;
 7 import java.util.concurrent.threadfactory;
 8 
 9 public class dmain {
10 
11     public static void main(string[] args) {
12         // todo auto-generated method stub
13 
14         completablefuture<string> onefuture = completablefuture.supplyasync(() -> {
15 
16             system.out.println("supplyasync用于新建");
17             return "2011";
18         });
19 
20         completablefuture<long> twofuture = onefuture.thenapply((ss) -> {
21             system.out.println("thenapply用于转化");
22             return long.parselong(ss);
23         });
24 
25         completablefuture<long> threefuture = twofuture.thencompose(val -> {
26             system.out.println("thencompose用于组合俩个completablefuture,但是依赖上一个completablefuture");
27             try {
28                 thread.sleep(2000);
29             } catch (interruptedexception e) {
30                 // todo auto-generated catch block
31                 e.printstacktrace();
32             }
33 
34             return completablefuture.supplyasync(() -> 
35             {
36                 long result = val * 2;
37                 system.out.println("thencompose的结果是:"+ result);
38                 return result;
39             }
40             
41             );
42         });
43 
44         completablefuture<string> otherfuture = completablefuture.supplyasync(() -> {
45             system.out.println("用于thencombine的测试  上面的结果+4");
46             return "4";
47         });
48 
49         completablefuture<long> finalfuture = threefuture.thencombine(otherfuture, (arg1, arg2) -> {
50             return arg1 + long.parselong(arg2);
51         });
52 
53         finalfuture.thenaccept((ss) -> {
54             system.out.println("thenaccept用于处理相关的结果数据");
55         });
56 
57         finalfuture.thenrun(() -> {
58             system.out.println("thenrun用于异步完成,执行相关的操作");
59         });
60 
61         try {
62             
63             system.out.println(finalfuture.get());
64         } catch (interruptedexception e) {
65             // todo auto-generated catch block
66             e.printstacktrace();
67         } catch (executionexception e) {
68             // todo auto-generated catch block
69             e.printstacktrace();
70         }
71 
72     }
73 
74 }

运行结果:

JAVA8给我带了什么——Optional和CompletableFuture

这个个方法的作用笔者略微的列了出来。想要加深的话,你们可能最好在去找一些资料。关于completablefuture的教程网络上很多。