zoukankan      html  css  js  c++  java
  • JAVA8给我带了什么——Optional和CompletableFuture

    不管是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 }

    运行结果:

    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来做文章。显示如下。

    当然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 }

    运行结果:

    我们可以到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"))

    运行结果:

    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 }

    运行结果:

    我们可以看到代码中的俩种方式了吧。这俩个方式都只有一个毛病。没有办法实现返回值的功能。所以引入了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 }

    运行结果:

    我可以看到一个叫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 }

    运行结果:

    看到了没有被取消了。同时你去获得取消线程的结果时,会发生异常。有没有.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 }

    运行结果:

    笔者在线程里面睡了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 }

    运行结果:

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

  • 相关阅读:
    Could A New Linux Base For Tablets/Smartphones Succeed In 2017?
    使用libhybris,glibc和bionic共存时的TLS冲突的问题
    6 Open Source Mobile OS Alternatives To Android in 2018
    Using MultiROM
    GPU drivers are written by the GPU IP vendors and they only provide Android drivers
    Jolla Brings Wayland Atop Android GPU Drivers
    How to Use Libhybris and Android GPU Libraries with Mer (Linux) on the Cubieboard
    闲聊Libhybris
    【ARM-Linux开发】wayland和weston的介绍
    Wayland and X.org problem : Why not following the Android Solution ?
  • 原文地址:https://www.cnblogs.com/hayasi/p/10660995.html
Copyright © 2011-2022 走看看