JDK8新特性

CompletableFutrue

实现线程的三种方法:

  1. 继承Thread类;
  2. 实现Runnable接口;
  3. 实现Callable<返回类型>接口。

实现Runnable接口没有返回值;Callable接口可以通过Future<T,>获取返回值。

使用Future

/*
* Callable接口是一个泛型接口,可以返回指定类型的结果。
*/
class Task implements Callable<String> {
    public String call() throws Exception {
        return longTimeCalculation(); 
    }
}

ExecutorService executor = Executors.newFixedThreadPool(4);
// 定义任务:
Callable<String> task = new Task();
// 提交任务并获得Future:
Future<String> future = executor.submit(task);
// 从Future获取异步执行返回的结果:
String result = future.get(); // 可能阻塞
System.out.println(result);

当我们提交一个Callable任务后,我们会同时获得一个Future对象,然后,我们在主线程某个时刻调用Future对象的get()方法,就可以获得异步执行的结果。在调用get()时,如果异步任务已经完成,我们就直接获得结果。如果异步任务还没有完成,那么get()会阻塞,直到任务完成后才返回结果。

使用CompletableFuture

从Java 8开始引入了CompletableFuture,它针对Future做了改进,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。

核心API1. completableFuture()/[supply|run](Async)/
2. Then[apply|accept|run](Both|Euther)(Async)
3. get() vs join()
4. allOf/anyOf
public class Main {
    public static void main(String[] args) throws Exception {
        // 创建异步执行任务:
        CompletableFuture<Double> cf = CompletableFuture.supplyAsync(Main::fetchPrice);
        // 如果执行成功:
        cf.thenAccept((result) -> {System.out.println("price: " + result);});
        // 如果执行异常:
        cf.exceptionally((e) -> {e.printStackTrace();  return null;});
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(200);
    }

    static Double fetchPrice() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        if (Math.random() < 0.3) {
            throw new RuntimeException("fetch price failed!");
        }
        return 5 + Math.random() * 20;
    }
}
  1. CompletableFuture.supplyAsync()实现的,它需要一个实现了Supplier接口的对象;
  2. 完成时,thenAccept()会调用Consumer对象;
  3. 异常时,exceptionally()会调用Function对象。

可见CompletableFuture的优点是:

  • 异步任务结束时,会自动回调某个对象的方法;
  • 异步任务出错时,会自动回调某个对象的方法;
  • 主线程设置好回调后,不再关心异步任务的执行。
串行执行
public class Main {
    public static void main(String[] args) throws Exception {
        // 第一个任务:
        CompletableFuture<String> cfQuery = CompletableFuture.supplyAsync(() -> {
            return queryCode("中国石油");
        })
        // cfQuery成功后继续执行下一个任务:
        .thenApplyAsync((code) -> {
            return fetchPrice(code);
        });
        // cfFetch成功后打印结果:
        .thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(2000);
    }

    static String queryCode(String name) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        return "601857";
    }

    static Double fetchPrice(String code) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        return 5 + Math.random() * 20;
    }
}
并行执行
public class Main {
    public static void main(String[] args) throws Exception {
        // 两个CompletableFuture执行异步查询:
        CompletableFuture<String> cfQueryFromSina = CompletableFuture.supplyAsync(() -> {return queryCode("中国石油", "https://finance.sina.com.cn/code/");});
        CompletableFuture<String> cfQueryFrom163 = CompletableFuture.supplyAsync(() -> {return queryCode("中国石油", "https://money.163.com/code/");});

        // 用anyOf合并为一个新的CompletableFuture:
        CompletableFuture<Object> cfQuery = CompletableFuture.anyOf(cfQueryFromSina, cfQueryFrom163);

        // 两个CompletableFuture执行异步查询:
        CompletableFuture<Double> cfFetchFromSina = cfQuery.thenApplyAsync((code) -> {            return fetchPrice((String) code, "https://finance.sina.com.cn/price/");});
        CompletableFuture<Double> cfFetchFrom163 = cfQuery.thenApplyAsync((code) -> {            return fetchPrice((String) code, "https://money.163.com/price/");});

        // 用anyOf合并为一个新的CompletableFuture:
        CompletableFuture<Object> cfFetch = CompletableFuture.anyOf(cfFetchFromSina, cfFetchFrom163);

        // 最终结果:
        cfFetch.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(200);
    }

    static String queryCode(String name, String url) {
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
        }
        return "601857";
    }

    static Double fetchPrice(String code, String url) {
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
        }
        return 5 + Math.random() * 20;
    }
}

总结:
ompletableFuture可以指定异步处理流程:

  • thenAccept()处理正常结果;
  • exceptional()处理异常结果;
  • thenApplyAsync()用于串行化另一个CompletableFuture;
  • anyOf()和allOf()用于并行化多个CompletableFuture。

Optional

Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException)。
如:

// 有可能报空指针异常
String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();

// 安全的,没有异常,但是代码冗余,不易维护
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

// 使用Optional后
String result = Optional.ofNullable(user)
      .flatMap(u -> u.getAddress())
      .flatMap(a -> a.getCountry())
      .map(c -> c.getIsocode())
      .orElse("default");

创建 Optional 实例

Optional<Object> empty = Optional.empty();
//empty.get(); // 报NoSuchElementException异常

Optional<Object> o = Optional.of(new Object());
Optional<Object> o1 = Optional.of(null);
o1.get(); // 报NullPointerException异常

Optional<Object> o2 = Optional.ofNullable(null);

orElse 和orElseGet

Optional 类提供了 API 用以返回对象值,或者在对象为空的时候返回默认值。

private User createNewUser() {
    logger.debug("Creating New User");
    return new User("extra@gmail.com", "1234");
}
  1. 当user为空的时候,两种方法都调用了 createNewUser() 方法。
User user = null;
logger.debug("Using orElse");
User result = Optional.ofNullable(user).orElse(createNewUser());
logger.debug("Using orElseGet");
User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
  1. 当user不为空的时候,orElseGet() 方法不调用 createNewUser()方法。
User user = new User("john@gmail.com", "1234");
logger.info("Using orElse");
User result = Optional.ofNullable(user).orElse(createNewUser());
logger.info("Using orElseGet");
User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());

map和flatMap

区别:map的返回值Optional对象是在map方法里面自动封装好了。而flatMap方法是自己的实现的逻辑中自己封装。

看源码:

  public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
      Objects.requireNonNull(mapper);
      if (!isPresent())
          return empty();
      else {
      	  // 这是返回的时候自动把返回值包装好了
          return Optional.ofNullable(mapper.apply(value));
      }
  }

  public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
      Objects.requireNonNull(mapper);
      if (!isPresent())
          return empty();
      else {
          return Objects.requireNonNull(mapper.apply(value));
      }
  }
  • map() 对值调用作为参数的函数,然后将返回的值包装在 Optional 中。
User user = new User("anna@gmail.com", "1234");
String email = Optional.ofNullable(user)
  .map(u -> u.getEmail()).orElse("default@gmail.com");
assertEquals(email, user.getEmail());
  • flatMap() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。
public class User {    
    private String position;
    public Optional<String> getPosition() {
        return Optional.ofNullable(position);
    }
}

User user = new User("anna@gmail.com", "1234");
user.setPosition("Developer");
String position = Optional.ofNullable(user)
  .flatMap(u -> u.getPosition()).orElse("default");
assertEquals(position, user.getPosition().get());

函数组合compose和andthen

Curry(柯里化)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抽抽了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值