Java8实战-总结51

CompletableFuture:组合式异步编程

响应 CompletableFuture 的 completion 事件

付诸实践

现在通过randomDelay方法模拟远程方法调用,产生一个介于0.5秒到2.5秒的随机延迟,不再使用恒定1秒的延迟值。下面的代码清单应用了这一改变,执行这段代码你会看到不同商店的价格不再像之前那样总是在一个时刻返回,而是随着商店折扣价格返回的顺序逐一地打印输出。为了让这一改变的效果更加明显,我们对代码进行了微调,在输出中打印每个价格计算所消耗的时间:

long start = System.nanoTime(); 
CompletableFuture[] futures = findPricesStream("myPhone27S")
    .map(f -> f.thenAccept(
        s -> System.out.println(s + " (done in " + ((System.nanoTime() - start) / 1_000_000) + " msecs)"))) 
    .toArray(size -> new CompletableFuture[size]); 
    
CompletableFuture.allOf(futures).join(); 

System.out.println("All shops have now responded in " 
         + ((System.nanoTime() - start) / 1_000_000) + " msecs"); 

运行这段代码所产生的输出如下:

BuyItAll price is 184.74 (done in 2005 msecs) 
MyFavoriteShop price is 192.72 (done in 2157 msecs) 
LetsSaveBig price is 135.58 (done in 3301 msecs) 
ShopEasy price is 167.28 (done in 3869 msecs) 
BestPrice price is 110.93 (done in 4188 msecs) 
All shops have now responded in 4188 msecs 

由于随机延迟的效果,第一次价格查询比最慢的查询要快两倍多。

小结

这部分的主要内容如下:

  • 执行比较耗时的操作时,尤其是那些依赖一个或多个远程服务的操作,使用异步任务可以改善程序的性能,加快程序的响应速度。
  • 应该尽可能地为客户提供异步API。使用CompletableFuture类提供的特性,能够轻松地实现这一目标。
  • CompletableFuture类还提供了异常管理的机制,让你有机会抛出/管理异步任务执行中发生的异常。
  • 将同步API的调用封装到一个CompletableFuture中,你能够以异步的方式使用其结果。
  • 如果异步任务之间相互独立,或者它们之间某一些的结果是另一些的输入,你可以将这异步任务构造或者合并成一个。
  • 你可以为CompletableFuture注册一个回调函数,在Future执行完毕或者它们计算的结果可用时,针对性地执行一些程序。
  • 你可以决定在什么时候结束程序的运行,是等待由CompletableFuture对象构成的列表中所有的对象都执行完毕,还是只要其中任何一个首先完成就中止程序的运行。

新的日期和时间AP

JavaAPI提供了很多有用的组件,能帮助你构建复杂的应用。不过,Java API也不总是完美的。大多数有经验的程序员都会赞同Java 8之前的库对日期和时间的支持就非常不理想。然而,也不用太担心:Java 8中引入全新的日期和时间API就是要解决这一问题。

Java 1.0中,对日期和时间的支持只能依赖java.util.Date类。正如类名所表达的,这个类无法表示日期,只能以毫秒的精度表示时间。更糟糕的是它的易用性,由于某些原因未知的设计决策,这个类的易用性被深深地损害了,比如:年份的起始选择是1900年,月份的起始从0开始。这意味着,如果你想要用Date表示Java 8的发布日期,即2014年3月18日,需要创建下面这样的Date实例:

Date date = new Date(114, 2, 18); 

它的打印输出效果为:

Tue Mar 18 00:00:00 CET 2014

看起来不那么直观。此外,甚至Date类的toString方法返回的字符串也容易误导人。以我们的例子而言,它的返回值中甚至还包含了JVM的默认时区CET,即中欧时间(Central Europe Time)。但这并不表示Date类在任何方面支持时区。

随着Java 1.0退出历史舞台,Date类的种种问题和限制几乎一扫而光,但很明显,这些历史旧账如果不牺牲前向兼容性是无法解决的。所以,在Java 1.1中,Date类中的很多方法被废弃了,取而代之的是java.util.Calendar类。很不幸,Calendar类也有类似的问题和设计缺陷,导致使用这些方法写出的代码非常容易出错。比如,月份依旧是从0开始计算(不过,至少Calendar类拿掉了由1900年开始计算年份这一设计)。更糟的是,同时存在DateCalendar这两个类,也增加了程序员的困惑。到底该使用哪一个类呢?此外,有的特性只在某一个类有提供,比如用于以语言无关方式格式化和解析日期或时间的DateFormat方法就只在Date类里有。

DateFormat方法也有它自己的问题。比如,它不是线程安全的。这意味着两个线程如果尝试使用同一个formatter解析日期,你可能会得到无法预期的结果。

所有这些缺陷和不一致导致用户们转投第三方的日期和时间库,比如Joda-Time。为了解决这些问题,Oracle决定在原生的Java API中提供高质量的日期和时间支持。所以,你会看到Java 8在java.time包中整合了很多Joda-Time的特性。

下面会探索新的日期和时间API所提供的新特性。首先从最基本的用例入手,比如创建同时适合人与机器的日期和时间,逐渐转入到日期和时间API更高级的一些应用,比如操纵、解析、打印输出日期时间对象,使用不同的时区和年历。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值