一、简介
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 voidtest1(){//原始代码
new Thread(newRunnable() {
@Overridepublic voidrun() {
System.out.println("I love lambda");
}
}).start();//使用lambda之后的效果
new Thread(() -> System.out.println("I love lambda")).start();
}
Lambda表达式-函数式接口:
函数接口指的是只有一个函数的接口,这样的接口可以隐式转换为Lambda表达式。在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的所有相关接口都已经带有这个注解了),上面代码中的 Runnable 就是函数式接口,源码如下:
自定义函数式接口
/*** 自定义函数式接口*/@FunctionalInterfacepublic interface FooIface{
R foo(T t, S s, U u);static voidtest2() {
}default voidtest1() {
}
}
值得注意的是,默认方法和静态方法不会破坏函数式接口的定义,因此以上的代码是合法的。
Lambda表达式-四大类函数式接口:
消费型
java.util.function.Consumer
public voidtestConsumer() {/*** 消费型
* 有参,无返回值*/Consumer consumer1 = new Consumer() {
@Overridepublic voidaccept(String s) {
System.out.println(s);
}
};
Consumer consumer2 = s ->System.out.println(s);
}
供给型
java.util.function.Supplier
public voidtestSupplier() {/*** 供给型
* 无参,有返回值
* () -> "hello";*/Supplier supplier1 = new Supplier() {
@OverridepublicString get() {return "hello";
}
};
Supplier supplier2 = () -> "hello";
}
断言型
java.util.function.Predicate
public voidtestPredicate() {/*** 断言型
* 有参数,返回值是boolean类型*/Predicate predicate1 = new Predicate() {
@Overridepublic booleantest(String s) {return s.startsWith("abc_");
}
};
Predicate predicate2 = s -> s.startsWith("abc_");
}
转化型
java.util.function.Function
public voidtestFunction() {/*** 转化型
* 有参数,有返回,但是参数和返回是不同的数据类型*/Function function1 = new Function() {
@OverridepublicInteger apply(String s) {returns.length();
}
};
Function function2 = s ->s.length();
Function function3 =String::length;
}
2、方法引用
方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。先来看一下下面这段代码:
public voidtest4() {/*** 方法引用
interface Comparator
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 comparator1 = new Comparator() {
@Overridepublic intcompare(Integer o1, Integer o2) {returnInteger.compare(o1, o2);
}
};//基于lambda改写后的,第一种写法,但是有冗余代码,比如return和代码块的大括号
Comparator comparator2 = (x, y) -> { returnInteger.compare(x, y); };//再一次改写,去掉了return,因为我明明知道就是要return,还需要你再写吗?
Comparator comparator3 = (x, y) ->Integer.compare(x, y);//最终,这两个形参x,y其实只是一个占位而已,接受者Integer::compare就知道有这样两个参数传进来,大家心知肚明的事情, 就省略嘛
Comparator 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 function = String::new;
Function function = ArrayList::new;
BiFunction biFunction = HashMap::new;
Function function = String[]::new;
静态方法引用
class::statisMethod
Comparator comparator = Integer::compare;
成员方法引用
class::Method
BiPredicate predicate = String::equals;
示例对象的方法引用
class::instanceMethod
Supplier supplier = linkedList::pop;
自定义类实现方法引用
public classStringLengthCompare {public static intabc(String o1, String o2) {return o1.length() > o2.length() ? 1 : -1;
}public intbcd(String o1, String o2) {return o1.length() > o2.length() ? 1 : -1;
}
}
StringLengthCompare 类
public voidtest5() {/*** 第一种,原始写法*/Comparator comparator = new Comparator() {
@Overridepublic intcompare(String o1, String o2) {return o1.length() > o2.length() ? 1 : -1;
}
};int res = comparator.compare("abc", "ab");
System.out.println(res);/*** 第二种,使用lambda改写*/Comparator comparator1 = (str1, str2) -> str1.length() > str2.length() ? 1 : -1;
res= comparator1.compare("abc", "ab");
System.out.println(res);/*** 第三种,自定义StringLengthCompare类实现方法引用*/
//abc为静态方法,直接用类名调用
Comparator comparator2 =StringLengthCompare::abc;
System.out.println("comparator2 = " +comparator2);//bcd为非静态方法,需要用对象来调用
StringLengthCompare stringLengthCompare = newStringLengthCompare();
Comparator comparator3 =stringLengthCompare::bcd;
System.out.println("comparator3 = " +comparator3);
}
3、接口的静态方法和默认方法
Java 8 使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得开发者可以在不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。接口提供的默认方法会被接口的实现类继承或者覆写,例子代码如下:
private interfaceDefaulable {//Interfaces now allow default methods, the implementer may or//may not implement (override) them.
defaultString notRequired() {return "Default implementation";
}
}
Defaulable
private static class DefaultableImpl implementsDefaulable {
}
DefaultableImpl
private static class OverridableImpl implementsDefaulable {
@OverridepublicString notRequired() {return "Overridden implementation";
}
}
OverridableImpl
Defaulable 接口使用关键字 default 定义了一个默认方法 notRequired()。DefaultableImpl 类实现了这个接口,同时默认继承了这个接口中的默认方法;OverridableImpl 类也实现了这个接口,但覆写了该接口的默认方法,并提供了一个不同的实现。
Java 8带来的另一个有趣的特性是在接口中可以定义静态方法,例子代码如下:
private interfaceDefaulableFactory {//Interfaces now allow static methods
static Defaulable create( Supplier< Defaulable >supplier ) {returnsupplier.get();
}
}
DefaulableFactory
下面的代码片段整合了默认方法和静态方法的使用场景:
public static voidmain( 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 classDemo {public static voidmain(String[] args) {/*** 创建Stream流,有三种方式*/
//第一种,集合类自带的方法
List list = new ArrayList<>();
Stream stream =list.stream();
Set set = null;
Stream stream1 =set.stream();//第二种,数组类流的创建
int[] arr = new int[]{1, 2, 3};
IntStream stream2=Arrays.stream(arr);/*** public static Stream of(T... values) {
* return Arrays.stream(values);
* }*/
//第三种,Stream接口自己提供的of方法,从实现来看是和第二种是一样的
Stream stream3 = Stream.of("", "", "");
}
}
创建Stream流的三种方式
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
@ToStringpublic classAccount {private intid;privateString accountName;private booleanisInner;private booleanisA;private booleanisB;private booleanisC;privateString type;private Listusers;privateAccount() {
}private Account(int id, String accountName, boolean isInner, String type, Listusers) {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, booleanisC,
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, booleanisInner, String type,
Listusers) {return newAccount(id, accountName, isInner, type, users);
}public static Account of(int id, String accountName, boolean isInner, boolean isA, booleanisB,booleanisC,
String type) {return newAccount(id, accountName, isInner, isA, isB, isC, type);
}
@Overridepublic booleanequals(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;
}
@Overridepublic inthashCode() {int result =id;
result= 31 * result + (accountName != null ? accountName.hashCode() : 0);returnresult;
}
}
Account
@Setter
@Getter
@ToStringpublic classUser {private intid;privateString name;privateUser() {
}private User(intid, String name) {this.id =id;this.name =name;
}public static User of(intid, String name) {return newUser(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);//}
@Overridepublic booleanequals(Object o) {if (this ==o) {return true;
}if (o == null || getClass() !=o.getClass()) {return false;
}
User user=(User) o;return id ==user.id;
}
@Overridepublic inthashCode() {returnObjects.hashCode(id);
}
}
User
生成 Account 对象集合的类 AccountFactory
public classAccountFactory {public static ListgetSimpleAccounts() {
List 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)));returnaccounts;
}public static ListgetSimpleABCAccounts() {
List 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, "出款"));returnaccounts;
}public static void printAccount(Listaccounts) {for(Account account : accounts) {
System.out.println("account = " +account);
}
}public static void printAccount(Map>accounts) {
accounts.forEach((key, val)->{
System.out.println("groupName:" +key);for(Account account : val) {
System.out.println("\t\t account:" +account);
}
});
}
}
AccountFactory
生成 User 对象集合的类 UserFactory
public classUserFactory {public static List getSimpleUsers(booleantype) {
List 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, "小淘气"));
}returnusers;
}public static ListgetSimpleUsers() {
List 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, "小淘气"));returnusers;
}
}
UserFactory
以下为测试代码:
public classStreamDemo1 {/*** 过滤:原始写法*/@Testpublic voidtest1() {
List accounts =AccountFactory.getSimpleAccounts();
List accs = new ArrayList<>();for(Account account : accounts) {if(account.isInner()) {
accs.add(account);
}
}
AccountFactory.printAccount(accs);
}/*** 过滤:java8写法*/@Testpublic voidtest2() {
List accounts =AccountFactory.getSimpleAccounts();
List accs =accounts
.stream()//创建流
.filter(Account::isInner) //中间操作
.collect(Collectors.toList()); //终止操作
AccountFactory.printAccount(accs);
}/*** 分组:原始写法*/@Testpublic voidtest3() {
List accounts =AccountFactory.getSimpleAccounts();
Map> group = new HashMap<>();for(Account account : accounts) {if(group.containsKey(account.getType())) {
group.get(account.getType()).add(account);
}else{
List acc = new ArrayList<>();
acc.add(account);
group.put(account.getType(), acc);
}
}
AccountFactory.printAccount(group);
}/*** 分组:java8的写法*/@Testpublic voidtest4() {
List accounts =AccountFactory.getSimpleAccounts();
Map> group =accounts
.stream()
.collect(Collectors.groupingBy(Account::getType));
AccountFactory.printAccount(group);
}/*** 分组, 对内部账户进行分组*/@Testpublic voidtest5() {
List accounts =AccountFactory.getSimpleAccounts();
Map> 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 acc = new ArrayList<>();
acc.add(account);
group.put(account.getType(), acc);
}
}
AccountFactory.printAccount(group);
}/*** 基于java8的分组,对内部账户进行分组*/@Testpublic voidtest6() {
List accounts =AccountFactory.getSimpleAccounts();
Map> group =accounts
.stream()
.filter(Account::isInner)
.filter(account-> !account.isB())
.filter(Account::isC)
.collect(Collectors.groupingBy(Account::getType));
AccountFactory.printAccount(group);
}
@Testpublic voidtest7() {/*** filter是中间操作
* filter操作完以后Stream对象类型不变*/Stream stream = Stream.of("abc_d", "ef", "abc_123")
.filter(str-> str.startsWith("abc_"));/*** collect是终止操作
* collect操作完以后Stream对象类型变成其他类型了*/List collect = Stream.of("abc_d", "ef", "abc_123")
.filter(str-> str.startsWith("abc_"))
.collect(Collectors.toList());for(String s : collect) {
System.out.println(s);
}
}
}
StreamDemo1
public classStreamDemo2 {/*** map:映射,获取对象的某个属性
* 返回所有内部账户的账户名*/@Testpublic voidtestMap() {
List accounts =AccountFactory.getSimpleAccounts();
List list =accounts.stream()
.filter(Account::isInner)
.map(Account::getAccountName)
.collect(Collectors.toList());for(String s : list) {
System.out.println(s);
}
}/*** skip:切片,去除前面几条*/@Testpublic voidtestSkip() {
List accounts =AccountFactory.getSimpleAccounts();
List list =accounts
.stream()
.skip(5)
.collect(Collectors.toList());for(Account account : list) {
System.out.println(account);
}
}/*** skip:切片,去除调前面几条
* limit:分页,控制结果的数量*/@Testpublic voidtestLimit() {
List accounts =AccountFactory.getSimpleAccounts();
List list =accounts
.stream()
.skip(3)
.limit(5)
.collect(Collectors.toList());for(Account account : list) {
System.out.println(account);
}
}/*** 拿出account中user列表的名字
*
* 去重*/@Testpublic voidtestflatMap() {
List accounts =AccountFactory.getSimpleAccounts();//这个搞不定
List> res =accounts.stream()
.map(account->{
List users =account.getUsers();returnusers.stream().map(User::getName).collect(Collectors.toList());
})
.distinct()
.collect(Collectors.toList());
System.out.println("res:" +res);
List 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);
}
}
StreamDemo2
public classStreamDemo3 {
@Testpublic voidtestMaxOrMin() {
List accounts =AccountFactory.getSimpleAccounts();
Optional 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);
}
@Testpublic voidtestForeach() {
List accounts =AccountFactory.getSimpleAccounts();
accounts.stream()
.filter(Account::isInner)
.map(Account::getId)
.forEach(System.out::println);
}
@Testpublic voidtestFind() {
List accounts =AccountFactory.getSimpleAccounts();
Optional optional =accounts.stream()
.filter(Account::isInner)
.map(Account::getId)
.findAny();
System.out.println("optional.get() = " +optional.get());
}
@Testpublic voidtestMatch() {
List accounts =AccountFactory.getSimpleAccounts();boolean match =accounts.stream()
.anyMatch(Account::isInner);
System.out.println("match = " +match);
}
@Testpublic voidtestMapForeach() {
Map mapData =Maps.newHashMap();
mapData.put("hello", "hi");
mapData.put("yes", "no");
mapData.forEach((key, val)->{
System.out.println(key+ "," +val);
});
}
}
StreamDemo3
public classStreamDemo4 {/*** 我以accountName作为key,来划分Account
*
* list = [account,account]
*
* map = {(accountName,account),(accountName,account)} map =
* {(accountName,account),(accountName,account)}*/@Testpublic voidtest1() {
List accounts =AccountFactory.getSimpleAccounts();
Map map =accounts
.stream()
.collect(Collectors.toMap(Account::getAccountName, account->account));
map.forEach((key, val)->{
System.out.println(key+ "," +val);
});
}
@Testpublic voidtest2(){
List accounts =AccountFactory.getSimpleAccounts();
Map map =accounts
.stream()
.collect(Collectors.toMap(Account::getAccountName, Account::getId));
map.forEach((key, val)->{
System.out.println(key+ "," +val);
});
}
}
StreamDemo4
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 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 Optional map(Function super T, ? extends U>mapper) {//如果入参mapper对象为null将抛NullPointerException异常
Objects.requireNonNull(mapper);//如果Optional对象的值为null,将直接返回该Optional对象
if (!isPresent())returnempty();//执行传入的lambda表达式,并返回经lambda表达式操作后的Optional对象
else{returnOptional.ofNullable(mapper.apply(value));
}
}
举例:
判断不为null然后进行操作
public classDemo {/*** 不为null时进行操作
* 原始写法*/
public static voiddoThing(String name) {if (name != null) {
System.out.println(name);
}
}//使用Optional的写法
public static voiddoThingOptional(String name) {
Optional.ofNullable(name).ifPresent(System.out::println);
}
}
多层级取值
public classDemo {//原始写法
public staticString getAddress(User user) {if (user != null) {
AddressEntity addressEntity=user.getAddressEntity();if (addressEntity != null) {
String address=addressEntity.getAddress();if (address != null && address.length() > 3) {returnaddress;
}
}
}return null;
}//使用Optional的写法
public staticString getAddressOptional(User user) {returnOptional.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。