七、Optional 类
Java应用中最常见的bug就是空值异常。在 Java 8 之前,Google Guava 引入了 Optionals 类来解决 NullPointerException,从而避免源码被各种 null 检查污染,以便开发者写出更加整洁的代码。Java 8 也将 Optional 加入了官方库。
Optional 提供了一些有用的方法来避免显式的 null 检查,我们可以通过以下实例来更好的了解 Optional 类的使用!
public class OptionalTester { public static void main(String[] args) { OptionalTester tester = new OptionalTester(); Integer value1 = null; Integer value2 = new Integer(10); // Optional.ofNullable - 允许传递为 null 参数 Optional<Integer> a = Optional.ofNullable(value1); // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException Optional<Integer> b = Optional.of(value2); System.out.println(tester.sum(a,b)); } public Integer sum(Optional<Integer> a, Optional<Integer> b){ // Optional.isPresent - 判断值是否存在 System.out.println("第一个参数值存在: " + a.isPresent()); System.out.println("第二个参数值存在: " + b.isPresent()); // Optional.orElse - 如果值存在,返回它,否则返回默认值 Integer value1 = a.orElse(new Integer(0)); //Optional.get - 获取值,值需要存在 Integer value2 = b.get(); return value1 + value2; } }
如果想要了解更多用法,可以参考这篇文章:Optional 官方 API
八、新的日期时间 API
Java 8引入了新的 Date-Time API(JSR 310) 来改进时间、日期的处理!
在旧版的 Java 中,日期时间 API 存在诸多问题,例如:
- 非线程安全:java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
- 设计很差:Java的日期/时间类的定义并不一致,在
java.util
和java.sql
的包中都有日期类,此外用于格式化和解析的类被定义在java.text
包中。java.util.Date
同时包含日期和时间,而java.sql.Date
仅包含日期,将其纳入java.sql
包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。 - 时区处理麻烦:日期类并不提供国际化,没有时区支持,因此 Java 引入了
java.util.Calendar
和java.util.TimeZone
类,但他们同样存在上述所有的问题。
因为上面这些原因,诞生了第三方库Joda-Time
,可以替代 Java 的时间管理 API 。
Java 8 中新的时间和日期管理 API 深受Joda-Time
影响,并吸收了很多Joda-Time
的精华,新的java.time
包包含了所有关于日期、时间、时区、Instant(跟日期类似但是精确到纳秒)、duration(持续时间)和时钟操作的类。
新设计的 API 认真考虑了这些类的不变性,如果某个实例需要修改,则返回一个新的对象。
接下来看看java.time
包中的关键类和各自的使用例子。
8.1、Clock类
Clock
类使用时区来返回当前的纳秒时间和日期。Clock
可以替代System.currentTimeMillis()
和TimeZone.getDefault()
,实例如下:
final Clock clock = Clock.systemUTC(); System.out.println( clock.instant() ); System.out.println( clock.millis() );
输出结果是
2021-02-24T12:24:54.678Z 1614169494678
8.2、LocalDate、LocalTime 和 LocalDateTime类
LocalDate、LocalTime 和 LocalDateTime 类,都是用于处理日期时间的 API,在处理日期时间时可以不用强制性指定时区。
8.2.1、LocalDate
LocalDate 仅仅包含ISO-8601日历系统中的日期部分,实例如下:
//获取当前日期 final LocalDate date = LocalDate.now(); //获取指定时钟的日期 final LocalDate dateFromClock = LocalDate.now( clock ); System.out.println( date ); System.out.println( dateFromClock );
输出结果:
2021-02-24 2021-02-24
8.2.2、LocalTime
LocalTime 仅仅包含该日历系统中的时间部分,实例如下:
//获取当前时间 final LocalTime time = LocalTime.now(); //获取指定时钟的时间 final LocalTime timeFromClock = LocalTime.now( clock ); System.out.println( time ); System.out.println( timeFromClock );
输出结果:
20:36:16.315 20:36:16.315
8.2.3、LocalDateTime
LocalDateTime 类包含了 LocalDate 和 LocalTime 的信息,但是不包含 ISO-8601 日历系统中的时区信息,实例如下:
//获取当前日期时间 final LocalDateTime datetime = LocalDateTime.now(); //获取指定时钟的日期时间 final LocalDateTime datetimeFromClock = LocalDateTime.now( clock ); System.out.println( datetime ); System.out.println( datetimeFromClock );
输出结果:
2021-02-24T20:38:13.633 2021-02-24T20:38:13.633
8.3、ZonedDateTime类
如果你需要特定时区的信息,则可以使用 ZoneDateTime,它保存有 ISO-8601 日期系统的日期和时间,而且有时区信息,实例如下:
// 获取当前时间日期 final ZonedDateTime zonedDatetime = ZonedDateTime.now(); //获取指定时钟的日期时间 final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock ); //获取纽约时区的当前时间日期 final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of("America/New_York") ); System.out.println( zonedDatetime ); System.out.println( zonedDatetimeFromClock ); System.out.println( zonedDatetimeFromZone );
输出结果:
2021-02-24T20:42:27.238+08:00[Asia/Shanghai] 2021-02-24T12:42:27.238Z 2021-02-24T07:42:27.241-05:00[America/New_York]
8.4、Duration类
Duration类,它持有的时间精确到秒和纳秒。利用它我们可以很容易得计算两个日期之间的不同,实例如下:
final LocalDateTime from = LocalDateTime.of( 2020, Month.APRIL, 16, 0, 0, 0 ); final LocalDateTime to = LocalDateTime.of( 2021, Month.APRIL, 16, 23, 59, 59 ); //获取时间差 final Duration duration = Duration.between( from, to ); System.out.println( "Duration in days: " + duration.toDays() ); System.out.println( "Duration in hours: " + duration.toHours() );
输出结果:
Duration in days: 365 Duration in hours: 8783
九、Base64
在 Java 7中,我们经常需要使用第三方库就可以进行 Base64 编码。
在 Java 8中,Base64 编码已经成为 Java 类库的标准,实例如下:
public class Tester { public static void main(String[] args) { final String text = "Base64 finally in Java 8!"; final String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) ); System.out.println( encoded ); final String decoded = new String(Base64.getDecoder().decode( encoded ), StandardCharsets.UTF_8 ); System.out.println( decoded ); } }
输出结果:
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ== Base64 finally in Java 8!
新的 Base64API 也支持 URL 和 MINE 的编码解码,详情可以查看具体类方法。
十、Nashorn JavaScript 引擎
从 JDK 1.8 开始,Nashorn 取代 Rhino(JDK 1.6, JDK1.7) 成为 Java 的嵌入式 JavaScript 引擎。它使用基于 JSR 292 的新语言特性,将 JavaScript 编译成 Java 字节码。
与先前的 Rhino 实现相比,这带来了 2 到 10 倍的性能提升,实例如下:
public class JavaScriptTester { public static void main(String[] args) { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn"); String name = "Hello World"; try { nashorn.eval("print('" + name + "')"); }catch(ScriptException e){ System.out.println("执行脚本错误: "+ e.getMessage()); } } }
输出结果:
Hello World
在实际的开发中,使用的比较少!
十一、总结
Java 8 使得 Java 平台又前进了一大步,尤其是 Stream 流操作,使用的时候非常的爽,整个代码看起来也更加的简洁、直观、舒服!
现在 JDK 已经更新到13了,在后期,小编也会陆续给大家介绍新特性,欢迎点赞吐槽!