[TOC]
1 原生Base64 API
對應Base64的操作,沒必要非要用第三方庫了。java8內(nèi)置的Base64 API位于 : java.util.Base64
// 編碼 --> 字節(jié)數(shù)組
byte[] bs = Base64.getEncoder().encode("java 8".getBytes(Charset.forName("UTF-8")));
// amF2YSA4
System.out.println(new String(bs));
// 編碼 --> 直接轉(zhuǎn)為String
String string = Base64.getEncoder().encodeToString("java 8".getBytes(Charset.forName("UTF-8")));
// amF2YSA4
System.out.println(string);
// 解碼
byte[] bs2 = Base64.getDecoder().decode(bs);
// java 8
System.out.println(new String(bs2));
2 為NPE而生的Optional容器
為空指針而生的Optional,貌似N就之前就在 google的 工具類 Guava
中出現(xiàn)了洒嗤。
public final class Optional<T> {
private final T value;
private Optional(T value) {
// value為null時,在這一步就會直接報錯,可以快速定位到NPE發(fā)生的位置
this.value = Objects.requireNonNull(value);
}
private Optional() {
this.value = null;
}
// 返回一個空的Optional實例
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
// ...
}
其實就是一個容器類绿满,將可能為空的對象包裝在容器中蒿赢。
獲取Optional實例
構(gòu)造器是私有的,可以通過以下方法獲取其實例:
// 1. 返回一個空的Optional實例
Optional<Object> empty = Optional.empty();
// 2. 內(nèi)部調(diào)用了有參數(shù)的構(gòu)造器,因此value != null 的情況下才能正常返回Optional實例
Optional.of(T value);
// 3. value可以是null
ofNullable(T value);
常用方法
- isPresent() : 如果值存在返回true泳赋,否則返回false
- get(): 容器內(nèi)部有值則將其返回,否則拋出NoSuchElementException
- orElse(T other): 容器內(nèi)部有值則將其返回,否則返回other
- orElseGet(Supplier<? extends T> other): 容器內(nèi)部有值則將其返回,否則返回供給型接口other的返回值
- orElseThrow(Supplier<? extends X> exceptionSupplier): 容器內(nèi)部有值則將其返回,否則拋出供給型接口other返回的異常
- filter(Predicate<? super T> predicate): 對容器中的值使用predicate過濾后,如果滿足條件則返回包含該值的Optional,否則返回空Optional
- map(Function<? super T, ? extends U> mapper): 該方法的源碼如下
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
// mapper不能是null
Objects.requireNonNull(mapper);
// 容器內(nèi)沒有值,返回空Optional
if (!isPresent())
return empty();
else {
// 容器內(nèi)有值,返回對容器中的值apply隱射函數(shù)后的值的Optional
return Optional.ofNullable(mapper.apply(value));
}
}
使用Optional
先來看一種別扭的寫法
Optional<User> user = ......;
if (user.isPresent()) {// 容器內(nèi)部的對象存在就使用它
return user.get().getName();
} else {// 否則返回默認值
return "default Value";
}
其實,這樣用和下面的寫法沒有任何區(qū)別:
User user = ......;
if (user != null) {
return user.getName();
} else {
return "default Value";
}
調(diào)用方法 isPresent()
, 其實和 obj!=null
是一模一樣的妇菱。
有了Optional,像下面這樣才比較優(yōu)雅:
Optional<User> user = ......;
return user.map(User::getName).orElse("default Value");
再來看個例子
public static class Person {
private String name;
private Addr addr;
public static class Addr {
private String city;
private String street;
}
}
// 獲取用戶的街道名,如果為空,返回"NotFound"
public String getPersonStreet(Person person) {
return Optional.ofNullable(person)//
.map(p -> p.getAddr())//
.map(a -> a.getStreet())//
.orElse("NotFound");
}
// 沒有Optional的時候,這個功能很可能就得這么寫了
public String getPersonStreet2(Person person) {
if (person != null) {
if (person.getAddr() != null) {
if (person.getAddr().getStreet() == null) {
return "NotFound";
}
return person.getAddr().getStreet();
}
}
return "NotFound";
}
總結(jié)
- Optional的出現(xiàn),并不是能夠避免NPE,只是能減少NPE的發(fā)生。-
- 在NPE發(fā)生時,Optional可以快速定位NPE的根源
同時,在使用Optional的時候,應該盡量避免那些不優(yōu)雅的寫法,不然Optional的出現(xiàn)及幾乎沒有任何意義了。鑒于此,有以下幾點建議:
- 盡量不要直接調(diào)用
isPresent()/get()
方法 - 不建議將Optional作為成員變量/方法入?yún)?/li>
- 應該盡量使用
map()/filter()/orElse()
等方法
3 升級版的interface
public interface Foo {
// 傳統(tǒng)的全區(qū)靜態(tài)常量
Integer max = 10000;
// 傳統(tǒng)的抽象方法
String get();
// 靜態(tài)方法(新特性)
static String bar() {
return "haha";
}
// default修飾的實例方法(新特性)
default String hello() {
return "hello";
}
}
這樣一來恶耽,有點類似于多繼承了密任,但是可能會有沖突:
- 類優(yōu)先原則
- 實現(xiàn)的多個接口中的方法若有沖突,只能實現(xiàn)一個偷俭,其他的必須舍棄
public class InterfaceTest {
static interface Walkable {
default void walk() {
System.out.println("walk() from Walkable");
}
}
static interface Speekable {
default void speek() {
System.out.println("walk() from Walkable");
}
default void walk() {
System.out.println("walk() from Walkable");
}
}
static class Dog implements Walkable, Speekable {
@Override
public void walk() {
// 1. 只能選擇多個同名default方法中的一個來實現(xiàn),其余的必須舍棄
Speekable.super.walk();
}
}
static class Animal {
public void walk() {
System.out.println("walk() from Animal");
}
}
static class Cat extends Animal implements Walkable {
}
public static void main(String[] args) {
Cat cat = new Cat();
// 2. 類優(yōu)先原則,此處的walk()來自于父類Animal,而不是接口Walkable
cat.walk(); // walk() from Animal
}
}
4 可重復的注解
在jdk1.8之前,java中的注解不能直接重復出現(xiàn)在同一個被他修飾的方法或?qū)傩陨侠嘶洹V荒芡ㄟ^數(shù)組或者其他方式來變向的實現(xiàn)這個需求。
在jdk1.8里,可以讓注解在同一個被修飾的方法或?qū)傩陨现貜统霈F(xiàn)涌萤。
public class AnnotationTest {
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Roles.class)
public static @interface Role {
String value();
}
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public static @interface Roles {
Role[] value();
}
public static class RepeatableAnnotationTest {
@Role("admin")
@Role("user")
public void doProcess() {
}
}
public static void main(String[] args) throws Exception {
RepeatableAnnotationTest obj = new RepeatableAnnotationTest();
Method method = obj.getClass().getDeclaredMethod("doProcess");
Role[] annotations = method.getAnnotationsByType(Role.class);
// @cn.xxx$Role(value=admin)
// @cn.xxx$Role(value=user)
Arrays.stream(annotations).forEach(System.out::println);
}
}
5 JavaScript引擎
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
Object ret = engine.eval("function add(i,j){return i+j;} add(1,1);");
//out: 2.0
System.out.println("out: " + ret);
}
6 JVM內(nèi)存模型變化
永久帶被移除,引入了Metaspace淹遵。
詳情可參看: http://blog.csdn.net/hylexus/article/details/53771460