一、简介
Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级。Java 8是 Java 自 Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。在本文中我们将学习这些新特性,并用实际的例子说明在什么场景下适合使用。
- 语言
- 编译器
- 库
- 工具
- JVM
二、Java语言的新特性
1、Lambda表达式
Lambda 表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理,函数式开发者非常熟悉这些概念。
Lambda 表达式的组成:
- 参数列表部分, 位于表达式左侧的括号内
- (o1,o2)->{}
- ()->{}
- x ->{}
- 语法标识符,或参数与代码体分隔符
- ->
- 代码块,代码体
- 一般多行代码使用括号包起来;
- 如果只有一行代码,可以省略括号不写;
- 有return则需写return带有返回值,如果没有则不写;
- (params) -> code-body
举例:
public void test1(){ // 原始代码 new Thread(new Runnable() { @Override public void run() { System.out.println("I love lambda"); } }).start(); // 使用lambda之后的效果 new Thread(() -> System.out.println("I love lambda")).start(); }
Lambda表达式-函数式接口:
函数接口指的是只有一个函数的接口,这样的接口可以隐式转换为Lambda表达式。在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的所有相关接口都已经带有这个注解了),上面代码中的 Runnable 就是函数式接口,源码如下:
自定义函数式接口
/** * 自定义函数式接口 */ @FunctionalInterface public interface FooIface<R, T, S, U> { R foo(T t, S s, U u); static void test2() { } default void test1() { } }
值得注意的是,默认方法和静态方法不会破坏函数式接口的定义,因此以上的代码是合法的。
Lambda表达式-四大类函数式接口:
消费型
- java.util.function.Consumer
public void testConsumer() { /** * 消费型 * 有参,无返回值 */ Consumer<String> consumer1 = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; Consumer<String> consumer2 = s -> System.out.println(s); }
供给型
- java.util.function.Supplier
public void testSupplier() { /** * 供给型 * 无参,有返回值 * () -> "hello"; */ Supplier<String> supplier1 = new Supplier<String>() { @Override public String get() { return "hello"; } }; Supplier<String> supplier2 = () -> "hello"; }
断言型
- java.util.function.Predicate
public void testPredicate() { /** * 断言型 * 有参数,返回值是boolean类型 */ Predicate<String> predicate1 = new Predicate<String>() { @Override public boolean test(String s) { return s.startsWith("abc_"); } }; Predicate<String> predicate2 = s -> s.startsWith("abc_"); }
转化型
- java.util.function.Function
public void testFunction() { /** * 转化型 * 有参数,有返回,但是参数和返回是不同的数据类型 */ Function<String, Integer> function1 = new Function<String, Integer>() { @Override public Integer apply(String s) { return s.length(); } }; Function<String, Integer> function2 = s -> s.length(); Function<String, Integer> function3 = String::length; }
2、方法引用
方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。先来看一下下面这段代码:
public void test4() { /** * 方法引用 interface Comparator<T> int compare(T o1, T o2); Integer#compare(int x, int y) public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } */ // 原始写法,java8之前 Comparator<Integer> comparator1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; // 基于lambda改写后的,第一种写法,但是有冗余代码,比如return和代码块的大括号 Comparator<Integer> comparator2 = (x, y) -> { return Integer.compare(x, y); }; // 再一次改写,去掉了return,因为我明明知道就是要return,还需要你再写吗? Comparator<Integer> comparator3 = (x, y) -> Integer.compare(x, y); // 最终,这两个形参x,y其实只是一个占位而已,接受者Integer::compare就知道有这样两个参数传进来,大家心知肚明的事情, 就省略嘛 Comparator<Integer> comparator4 = Integer::compare; int x = 10; int y = 20; System.out.println(comparator1.compare(x, y)); System.out.println(comparator2.compare(x, y)); System.out.println(comparator3.compare(x, y)); System.out.println(comparator4.compare(x, y)); }
以上这段代码写了从最原始的写法到使用 Lambda 改写后的写法再到最终的方法引用。
方法引用包括四类:
构造方法引用
- Supplier supplier = String::new;
- Function<String, String> function = String::new;
- Function<Integer, List> function = ArrayList::new;
- BiFunction<Integer, Float, HashMap> biFunction = HashMap::new;
- Function<Integer, String[]> function = String[]::new;
静态方法引用
- class::statisMethod
- Comparator comparator = Integer::compare;
成员方法引用
- class::Method
- BiPredicate<String, String> predicate = String::equals;
示例对象的方法引用
- class::instanceMethod
- Supplier supplier = linkedList::pop;
自定义类实现方法引用
public class StringLengthCompare { public static int abc(String o1, String o2) { return o1.length() > o2.length() ? 1 : -1; } public int bcd(String o1, String o2) { return o1.length() > o2.length() ? 1 : -1; } }
public void test5() { /** * 第一种,原始写法 */ Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() > o2.length() ? 1 : -1; } }; int res = comparator.compare("abc", "ab"); System.out.println(res); /** * 第二种,使用lambda改写 */ Comparator<String> comparator1 = (str1, str2) -> str1.length() > str2.length() ? 1 : -1; res = comparator1.compare("abc", "ab"); System.out.println(res); /** * 第三种,自定义StringLengthCompare类实现方法引用 */ // abc为静态方法,直接用类名调用 Comparator<String> comparator2 = StringLengthCompare::abc; System.out.println("comparator2 = " + comparator2); // bcd为非静态方法,需要用对象来调用 StringLengthCompare stringLengthCompare = new StringLengthCompare(); Comparator<String> comparator3 = stringLengthCompare::bcd; System.out.println("comparator3 = " + comparator3); }
3、接口的静态方法和默认方法
Java 8 使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得开发者可以在不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。接口提供的默认方法会被接口的实现类继承或者覆写,例子代码如下:
private interface Defaulable { // Interfaces now allow default methods, the implementer may or // may not implement (override) them. default String notRequired() { return "Default implementation"; } }
private static class DefaultableImpl implements Defaulable { }
private static class OverridableImpl implements Defaulable { @Override public String notRequired() { return "Overridden implementation"; } }
Defaulable 接口使用关键字 default 定义了一个默认方法 notRequired()。DefaultableImpl 类实现了这个接口,同时默认继承了这个接口中的默认方法;OverridableImpl 类也实现了这个接口,但覆写了该接口的默认方法,并提供了一个不同的实现。
Java 8带来的另一个有趣的特性是在接口中可以定义静态方法,例子代码如下:
private interface DefaulableFactory { // Interfaces now allow static methods static Defaulable create( Supplier< Defaulable > supplier ) { return supplier.get(); } }
下面的代码片段整合了默认方法和静态方法的使用场景:
public static void main( String[] args ) { Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new ); System.out.println( defaulable.notRequired() ); defaulable = DefaulableFactory.create( OverridableImpl::new ); System.out.println( defaulable.notRequired() ); }
这段代码输入结果如下:
Default implementation
Overridden implementation
由于JVM上的默认方法的实现在字节码层面提供了支持,因此效率非常高。默认方法允许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()、parallelStream()、forEach() 和removeIf() 等等。尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引起歧义和编译错误。
注意:实现接口的类或者子接口不会继承接口中的静态方法
4、重复注解
在 Java学习之==>注解 这篇文章中有关于重复注解的介绍和使用。重复注解也是在 Java 8 中才开始支持的。
三、Java 官方库的新特性
1、Streams
新增的 Stream API(java.util.stream)将函数式编程引入了 Java 库中。这是目前为止最大的一次对 Java 库的完善,以便开发者能够写出更加有效、更加简洁和紧凑的代码。Steam API 极大的简化了集合操作(后面我们会看到不止是集合)。
Stream概述
- 非主流式定义: 像写SQL一样来处理集合;
- 理解类定义: 流式处理;
- 流式处理学习路线: 创建,操作(中间操作,终止操作);
Stream创建
- Collection等集合接口实现的stream()方法和parallelStream()方法;
- Arrays提供的数组流;
- Stream类提供的静态创建方法of();
public class Demo { public static void main(String[] args) { /** * 创建Stream流,有三种方式 */ // 第一种,集合类自带的方法 List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); Set<String> set = null; Stream<String> stream1 = set.stream(); // 第二种,数组类流的创建 int[] arr = new int[]{1, 2, 3}; IntStream stream2 = Arrays.stream(arr); /** * public static<T> Stream<T> of(T... values) { * return Arrays.stream(values); * } */ // 第三种,Stream接口自己提供的of方法,从实现来看是和第二种是一样的 Stream<String> stream3 = Stream.of("", "", ""); } }
Stream中间操作
- 过滤::filter;
- 切片 & 分页:sklip , limit;
- 去重:distinct(去重的对象需要实现hashCode和equals);
- 映射:map, flatMap;
- 排序:sort;
Stream终止操作
- 匹配
- allMatch:检查是否匹配所有元素;
- anyMatch:检查是否匹配至少一个元素;
- noneMatch:检查是否没有匹配所有元素
- 查找
- findFirst:查找找到的第一个元素;
- findAny:查找找到的任意一个元素
- 计算流中元素个数:count();
- 计算流中元素的最大/最小值:max() , min();
- 内部迭代:forEach;
- 收集:collect;
下面我们来举例操作一下:
首先定义两个实体类 Account 和 User
@Setter @Getter @ToString public class Account { private int id; private String accountName; private boolean isInner; private boolean isA; private boolean isB; private boolean isC; private String type; private List<User> users; private Account() { } private Account(int id, String accountName, boolean isInner, String type, List<User> users) { this.id = id; this.accountName = accountName; this.isInner = isInner; this.type = type; this.users = users; } public Account(int id, String accountName, boolean isInner, boolean isA, boolean isB, boolean isC, String type) { this.id = id; this.accountName = accountName; this.isInner = isInner; this.isA = isA; this.isB = isB; this.isC = isC; this.type = type; } public static Account of(int id, String accountName, boolean isInner, String type, List<User> users) { return new Account(id, accountName, isInner, type, users); } public static Account of(int id, String accountName, boolean isInner, boolean isA, boolean isB, boolean isC, String type) { return new Account(id, accountName, isInner, isA, isB, isC, type); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Account account = (Account) o; if (id != account.id) { return false; } return accountName != null ? accountName.equals(account.accountName) : account.accountName == null; } @Override public int hashCode() { int result = id; result = 31 * result + (accountName != null ? accountName.hashCode() : 0); return result; } }
@Setter @Getter @ToString public class User { private int id; private String name; private User() { } private User(int id, String name) { this.id = id; this.name = name; } public static User of(int id, String name) { return new User(id, name); } // @Override // public boolean equals(Object o) { // if (this == o) { // return true; // } // if (o == null || getClass() != o.getClass()) { // return false; // } // User user = (User) o; // return id == user.id && // Objects.equal(name, user.name); // } // // @Override // public int hashCode() { // return Objects.hashCode(id, name); // } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } User user = (User) o; return id == user.id; } @Override public int hashCode() { return Objects.hashCode(id); } }
生成 Account 对象集合的类 AccountFactory
public class AccountFactory { public static List<Account> getSimpleAccounts() { List<Account> accounts = new ArrayList<>(); accounts.add(Account.of(1, "微信支付1账户", false, "出款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(2, "微信支付2账户", false, "入款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(3, "微信支付3账户", true, "出款", UserFactory.getSimpleUsers(false))); accounts.add(Account.of(4, "微信支付4账户", true, "入款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(5, "微信支付5账户", false, "出款", UserFactory.getSimpleUsers(false))); accounts.add(Account.of(6, "微信支付6账户", false, "入款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(7, "微信支付7账户", false, "出款", UserFactory.getSimpleUsers(false))); accounts.add(Account.of(8, "微信支付8账户", true, "出款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(9, "微信支付9账户", true, "入款", UserFactory.getSimpleUsers(false))); accounts.add(Account.of(10, "微信支付10账户", true, "出款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(11, "微信支付11账户", true, "入款", UserFactory.getSimpleUsers(true))); accounts.add(Account.of(12, "微信支付12账户", false, "出款", UserFactory.getSimpleUsers(true))); return accounts; } public static List<Account> getSimpleABCAccounts() { List<Account> accounts = new ArrayList<>(); accounts.add(Account.of(1, "微信支付1账户", false, false, true, true, "出款")); accounts.add(Account.of(2, "微信支付2账户", false, false, false, true, "入款")); accounts.add(Account.of(3, "微信支付3账户", true, false, true, false, "出款")); accounts.add(Account.of(4, "微信支付4账户", true, false, true, true, "入款")); accounts.add(Account.of(5, "微信支付5账户", false, false, false, false, "出款")); accounts.add(Account.of(6, "微信支付6账户", false, false, true, true, "入款")); accounts.add(Account.of(7, "微信支付7账户", false, false, false, false, "出款")); accounts.add(Account.of(8, "微信支付8账户", true, false, false, true, "出款")); accounts.add(Account.of(9, "微信支付9账户", true, false, true, true, "入款")); accounts.add(Account.of(10, "微信支付10账户", true, false, false, false, "出款")); accounts.add(Account.of(11, "微信支付11账户", true, false, false, true, "入款")); accounts.add(Account.of(12, "微信支付12账户", false, false, true, true, "出款")); return accounts; } public static void printAccount(List<Account> accounts) { for (Account account : accounts) { System.out.println("account = " + account); } } public static void printAccount(Map<String, List<Account>> accounts) { accounts.forEach((key, val) -> { System.out.println("groupName:" + key); for (Account account : val) { System.out.println(" account:" + account); } }); } }
生成 User 对象集合的类 UserFactory
public class UserFactory { public static List<User> getSimpleUsers(boolean type) { List<User> users = Lists.newArrayList(); if (type) { users.add(User.of(1, "张三")); users.add(User.of(1, "李四")); users.add(User.of(1, "王五")); } else { users.add(User.of(1, "张三")); users.add(User.of(1, "李四")); users.add(User.of(1, "王五")); users.add(User.of(1, "王二麻子")); users.add(User.of(1, "小淘气")); } return users; } public static List<User> getSimpleUsers() { List<User> users = Lists.newArrayList(); users.add(User.of(1, "张三")); users.add(User.of(1, "李四")); users.add(User.of(1, "王五")); users.add(User.of(1, "王五")); users.add(User.of(1, "王五")); users.add(User.of(1, "王五")); users.add(User.of(1, "王五")); users.add(User.of(1, "王二麻子")); users.add(User.of(1, "小淘气")); return users; } }
以下为测试代码:
public class StreamDemo1 { /** * 过滤:原始写法 */ @Test public void test1() { List<Account> accounts = AccountFactory.getSimpleAccounts(); List<Account> accs = new ArrayList<>(); for (Account account : accounts) { if (account.isInner()) { accs.add(account); } } AccountFactory.printAccount(accs); } /** * 过滤:java8写法 */ @Test public void test2() { List<Account> accounts = AccountFactory.getSimpleAccounts(); List<Account> accs = accounts .stream() // 创建流 .filter(Account::isInner) // 中间操作 .collect(Collectors.toList()); // 终止操作 AccountFactory.printAccount(accs); } /** * 分组:原始写法 */ @Test public void test3() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Map<String, List<Account>> group = new HashMap<>(); for (Account account : accounts) { if (group.containsKey(account.getType())) { group.get(account.getType()).add(account); } else { List<Account> acc = new ArrayList<>(); acc.add(account); group.put(account.getType(), acc); } } AccountFactory.printAccount(group); } /** * 分组:java8的写法 */ @Test public void test4() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Map<String, List<Account>> group = accounts .stream() .collect(Collectors.groupingBy(Account::getType)); AccountFactory.printAccount(group); } /** * 分组, 对内部账户进行分组 */ @Test public void test5() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Map<String, List<Account>> group = new HashMap<>(); for (Account account : accounts) { if (!account.isInner()) { continue; } if (account.isA()) { continue; } if (!account.isB()) { continue; } if (group.containsKey(account.getType())) { group.get(account.getType()).add(account); } else { List<Account> acc = new ArrayList<>(); acc.add(account); group.put(account.getType(), acc); } } AccountFactory.printAccount(group); } /** * 基于java8的分组,对内部账户进行分组 */ @Test public void test6() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Map<String, List<Account>> group = accounts .stream() .filter(Account::isInner) .filter(account -> !account.isB()) .filter(Account::isC) .collect(Collectors.groupingBy(Account::getType)); AccountFactory.printAccount(group); } @Test public void test7() { /** * filter是中间操作 * filter操作完以后Stream对象类型不变 */ Stream<String> stream = Stream.of("abc_d", "ef", "abc_123") .filter(str -> str.startsWith("abc_")); /** * collect是终止操作 * collect操作完以后Stream对象类型变成其他类型了 */ List<String> collect = Stream.of("abc_d", "ef", "abc_123") .filter(str -> str.startsWith("abc_")) .collect(Collectors.toList()); for (String s : collect) { System.out.println(s); } } }
public class StreamDemo2 { /** * map:映射,获取对象的某个属性 * 返回所有内部账户的账户名 */ @Test public void testMap() { List<Account> accounts = AccountFactory.getSimpleAccounts(); List<String> list = accounts.stream() .filter(Account::isInner) .map(Account::getAccountName) .collect(Collectors.toList()); for (String s : list) { System.out.println(s); } } /** * skip:切片,去除前面几条 */ @Test public void testSkip() { List<Account> accounts = AccountFactory.getSimpleAccounts(); List<Account> list = accounts .stream() .skip(5) .collect(Collectors.toList()); for (Account account : list) { System.out.println(account); } } /** * skip:切片,去除调前面几条 * limit:分页,控制结果的数量 */ @Test public void testLimit() { List<Account> accounts = AccountFactory.getSimpleAccounts(); List<Account> list = accounts .stream() .skip(3) .limit(5) .collect(Collectors.toList()); for (Account account : list) { System.out.println(account); } } /** * 拿出account中user列表的名字 * * 去重 */ @Test public void testflatMap() { List<Account> accounts = AccountFactory.getSimpleAccounts(); // 这个搞不定 List<List<String>> res = accounts.stream() .map(account -> { List<User> users = account.getUsers(); return users.stream().map(User::getName).collect(Collectors.toList()); }) .distinct() .collect(Collectors.toList()); System.out.println("res:" + res); List<String> res2 = accounts.stream() // [[1,2],[1,2,3],[1,2,3,4]] .flatMap(account -> account.getUsers().stream()) //[1,2,1,2,3,1,2,3,4] .map(User::getName) .distinct() .collect(Collectors.toList()); System.out.println("res2:" + res2); } }
public class StreamDemo3 { @Test public void testMaxOrMin() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Optional<Integer> optional = accounts.stream() .filter(Account::isInner) .map(Account::getId) /** * peek,调试时输出值 */ .peek(System.out::println) .max(Integer::compare); Integer maxId = optional.get(); System.out.println("maxId = " + maxId); } @Test public void testForeach() { List<Account> accounts = AccountFactory.getSimpleAccounts(); accounts.stream() .filter(Account::isInner) .map(Account::getId) .forEach(System.out::println); } @Test public void testFind() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Optional<Integer> optional = accounts.stream() .filter(Account::isInner) .map(Account::getId) .findAny(); System.out.println("optional.get() = " + optional.get()); } @Test public void testMatch() { List<Account> accounts = AccountFactory.getSimpleAccounts(); boolean match = accounts.stream() .anyMatch(Account::isInner); System.out.println("match = " + match); } @Test public void testMapForeach() { Map<String, String> mapData = Maps.newHashMap(); mapData.put("hello", "hi"); mapData.put("yes", "no"); mapData.forEach((key, val) -> { System.out.println(key + "," + val); }); } }
public class StreamDemo4 { /** * 我以accountName作为key,来划分Account * * list<account> = [account,account] * * map<string,account> = {(accountName,account),(accountName,account)} map<string,account.id> = * {(accountName,account),(accountName,account)} */ @Test public void test1() { List<Account> accounts = AccountFactory.getSimpleAccounts(); Map<String, Account> map = accounts .stream() .collect(Collectors.toMap(Account::getAccountName, account -> account)); map.forEach((key, val) -> { System.out.println(key + "," + val); }); } @Test public void test2(){ List<Account> accounts = AccountFactory.getSimpleAccounts(); Map<String, Integer> map = accounts .stream() .collect(Collectors.toMap(Account::getAccountName, Account::getId)); map.forEach((key, val) -> { System.out.println(key + "," + val); }); } }
2、Date/Time API(JSR 310)
3、Optional
简介
- Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent() 方法会返回true,调用get()方法会返回该对象。
- Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
- Optional 类的引入很好的解决空指针异常。
类的属性和方法
从图中我们可以看出,它的构造方法都是private修饰的,其实是一个单例模式的应用。
下面我们主要来讲一下 filter() 和 map() 方法:
filter 方法
该方法是过滤方法,过滤符合条件的 Optional 对象,这里的条件用 Lambda 表达式来定义,源码如下:
public Optional<T> filter(Predicate<? super T> predicate) { //如果入参predicate对象为null将抛NullPointerException异常 Objects.requireNonNull(predicate); //如果Optional对象的值为null,将直接返回该Optional对象 if (!isPresent()) return this; //如果Optional对象的值符合限定条件(Lambda表达式来定义),返回该值,否则返回空的Optional对象 else return predicate.test(value) ? this : empty(); }
map 方法
map方法用于修改该值,并返回修改后的Optional对象,一般会在多级取值的时候用到,源码如下:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { //如果入参mapper对象为null将抛NullPointerException异常 Objects.requireNonNull(mapper); //如果Optional对象的值为null,将直接返回该Optional对象 if (!isPresent()) return empty(); //执行传入的lambda表达式,并返回经lambda表达式操作后的Optional对象 else { return Optional.ofNullable(mapper.apply(value)); } }
举例:
判断不为null然后进行操作
public class Demo { /** * 不为null时进行操作 * 原始写法 */ public static void doThing(String name) { if (name != null) { System.out.println(name); } } // 使用Optional的写法 public static void doThingOptional(String name) { Optional.ofNullable(name).ifPresent(System.out::println); } }
多层级取值
public class Demo { // 原始写法 public static String getAddress(User user) { if (user != null) { AddressEntity addressEntity = user.getAddressEntity(); if (addressEntity != null) { String address = addressEntity.getAddress(); if (address != null && address.length() > 3) { return address; } } } return null; } // 使用Optional的写法 public static String getAddressOptional(User user) { return Optional.ofNullable(user) .map(u -> u.getAddressEntity()) .map(a -> a.getAddress()) .filter(s -> s.length() > 3) .orElse(null); } }
四、JVM 的新特性
使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。