G1 成為默認垃圾回收器
在 Java 8 的時候,默認垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被廢棄了,G1(Garbage-First Garbage Collector) 成為了默認垃圾回收器。
G1 還是在 Java 7 中被引入的,經過兩個版本優異的表現成為成為默認垃圾回收器。
集合新增工廠方法
增加了List.of()
、Set.of()
、Map.of()
?和?Map.ofEntries()
等工廠方法來創建不可變集合(有點參考 Guava 的味道)
使用?of()
?創建的集合為不可變集合,不能進行添加、刪除、替換、 排序等操作,不然會報?java.lang.UnsupportedOperationException
?異常。
List list = List.of("張三", "李四", "王五", "趙六", "田七"); list.forEach(System.out::println);Set set = Set.of("張三", "李四", "王五", "趙六", "田七");set.forEach(System.out::println);Map map = Map.of("張三","張三", "李四","李四", "王五","王五", "趙六","趙六", "田七", "田七");map.forEach((k,v)->{System.out.println("k: "+k+" v: "+v);});list.add("xx"); //拋異常
String 存儲結構優化
Java 8 及之前的版本,String
?一直是用?char[]
?存儲。在 Java 9 之后,String
?的實現改用?byte[]
?數組存儲字符串,節省了空間。
String類的當前實現將字符存儲在char數組中,每個字符使用兩個字節(十六位)。從許多不同應用程序收集的數據表明,字符串是堆使用的主要組成部分,此外,大多數String對象只包含Latin-1個字符。此類字符只需要一個字節的存儲空間,因此此類String對象的內部char數組中有一半的空間未被使用。
java8String
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];
java9String
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/*** The value is used for character storage.** @implNote This field is trusted by the VM, and is a subject to* constant folding if String instance is constant. Overwriting this* field after construction will cause problems.** Additionally, it is marked with {@link Stable} to trust the contents* of the array. No other facility in JDK provides this functionality (yet).* {@link Stable} is safe here, because value is never null.*/@Stableprivate final byte[] value;
改進的 Stream API
?????????java 的 Steam API 是java標準庫最好的改進之一, 讓開發者能夠快速運算,從而能夠有效的利用數據并行計算。 Java 8 提供的 Steam 能夠利用多核架構實現聲明式的數據處理。
在 Java 9 中, Stream API 變得更好, Stream 接口中添加了 4 個新的方法:
takeWhile, dropWhile, ofNullable,還有個 iterate 方法的新重載方法,可以讓你提供一個 Predicate (判斷條件)來指定什么時候結束迭代。
除了對 Stream 本身的擴展, Optional 和 Stream 之間的結合也得到了改進。現在可以通過 Optional 的新方法 stream() 將一個 Optional 對象轉換為一個(可能是空的) Stream 對象。
ofNullable 方法
????????當創建流的元素可能為空時,使用ofNullable()方法代替of()方法可以預防 NullPointerExceptions 異常,創建流時可以省去判空的邏輯條件。元素為null返回空流,否則返回正常流。
public static<T> Stream<T> ofNullable(T t) {return t == null ? Stream.empty(): StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); }
Stream<Object> objectStream1 = Stream.ofNullable(null);//不報錯Stream<Object> objectStream = Stream.of(null);//報錯
takeWhile
takeWhile() 方法使用一個斷言作為參數,返回給定 Stream 的子集直到斷言語句第一次返回 false。如果第一個值不滿足斷言條件,將返回一個空的 Stream。
takeWhile() 方法在有序的 Stream 中,takeWhile 返回從開頭開始到不符合斷言條件的前一個元素;在無序的 Stream 中,takeWhile 返回從開頭開始的符合 Predicate 要求的所有元素的子集(包括空集)。
List<String> list = List.of("a", "b", "c", "", "e", "f");Set<String> set = Set.of("a", "b", "c", "", "e", "f");//abclist.stream().takeWhile(s -> !s.isEmpty()).forEach(System.out::print);System.out.println();//efabc 可能得結果a/ab/abc/abcef/b/bc/bcef/c/ce/cef/e/ef/f/空 且順序是亂的set.stream().takeWhile(s -> !s.isEmpty()).forEach(System.out::print);System.out.println();//bac 順序可能會亂但是穩定一直是abc三個元素list.parallelStream().takeWhile(s -> !s.isEmpty()).forEach(System.out::print);System.out.println();//bef 同第二條set.parallelStream().takeWhile(s -> !s.isEmpty()).forEach(System.out::print);
dropWhile
dropWhile 方法和 takeWhile 作用相反的,使用一個斷言作為參數,直到斷言語句第一次返回 false 才返回給定 Stream 的子集。
dropWhile () 方法在有序的 Stream 中,takeWhile 返回從不符合斷言條件的后一個元素開始到結尾,并行流也一樣
dropWhile () 方法在無序的 順序Stream 中,返回從開頭開始的符合 Predicate 要求的所有元素的子集(包括空集)。并行流只要中間有不符合的元素則返回null
List<String> list = List.of("a", "b", "c", "", "e", "f");Set<String> set = Set.of("a", "b", "c", "", "e", "f");//eflist.stream().dropWhile(s -> !s.isEmpty()).forEach(System.out::print);System.out.println();//efabc 可能得結果a/ab/abc/abcef/b/bc/bcef/c/ce/cef/e/ef/f/空 且順序是亂的set.stream().dropWhile(s -> !s.isEmpty()).forEach(System.out::print);System.out.println();//eflist.parallelStream().dropWhile(s -> !s.isEmpty()).forEach(System.out::print);System.out.println();// nullset.parallelStream().dropWhile(s -> !s.isEmpty()).forEach(System.out::print);
iterate
方法允許使用初始種子值創建順序(可能是無限)流,并迭代應用指定的下一個方法。 當指定的 hasNext 的 predicate 返回 false 時,迭代停止。
第一個參數是int類型,第二個參數是迭代條件,第三個參數返回值作為下一次迭代的初始值
public static IntStream iterate(int seed, IntPredicate hasNext, IntUnaryOperator next) {Objects.requireNonNull(next);Objects.requireNonNull(hasNext);Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE,Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {int prev;boolean started, finished;@Overridepublic boolean tryAdvance(IntConsumer action) {Objects.requireNonNull(action);if (finished)return false;int t;if (started)t = next.applyAsInt(prev);else {t = seed;started = true;}if (!hasNext.test(t)) {finished = true;return false;}action.accept(prev = t);return true;}@Overridepublic void forEachRemaining(IntConsumer action) {Objects.requireNonNull(action);if (finished)return;finished = true;int t = started ? next.applyAsInt(prev) : seed;while (hasNext.test(t)) {action.accept(t);t = next.applyAsInt(t);}}};return StreamSupport.intStream(spliterator, false); }
IntStream.iterate(-1, a -> true, a -> a + 1).forEach(System.out::println);
Optional 增強
Optional 類在 Java 8 中引入,Optional 類的引入很好的解決空指針異常。在 Java 9 中, 添加了三個方法來改進它的功能:
- stream()
- ifPresentOrElse()
- or()
stream()?
stream 方法的作用就是將 Optional 轉為一個 Stream,如果該 Optional 中包含值,那么就返回包含這個值的 Stream,否則返回一個空的 Stream(Stream.empty())。
List<Optional<String>> list = Arrays.asList (Optional.empty(),Optional.of("A"),Optional.empty(),Optional.of("B"));List<String> collect = list.stream().flatMap(Optional::stream).collect(Collectors.toList());System.out.println(collect);
ifPresentOrElse()?
ifPresentOrElse 方法的改進就是有了 else,接受兩個參數 Consumer 和 Runnable。
ifPresentOrElse 方法的用途是,如果一個 Optional 包含值,則對其包含的值調用函數 action,即 action.accept(value),這與 ifPresent 一致;與 ifPresent 方法的區別在于,ifPresentOrElse 還有第二個參數 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便會調用 emptyAction,即 emptyAction.run()。雖然是.run(),但也是同步方法,不是異步
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {if (value != null) {action.accept(value);} else {emptyAction.run();} }
Optional<Integer> optional = Optional.empty();optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->{try {Thread.sleep(200);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("Not Present.");} );Optional<Integer> optional1 = Optional.of(1);optional1.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->System.out.println("Not Present."));
or()?
如果值存在,返回 Optional 指定的值,否則返回一個預設的值。
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {Objects.requireNonNull(supplier);if (isPresent()) {return this;} else {@SuppressWarnings("unchecked")Optional<T> r = (Optional<T>) supplier.get();return Objects.requireNonNull(r);} }
Optional<String> optional = Optional.empty();optional = optional.or( () -> Optional.of("Not Present"));//Value: Not Presentoptional.ifPresent( x -> System.out.println("Value: " + x));Optional<String> optional1 = Optional.of("1");optional1 = optional1.or( () -> Optional.of("Not Present"));//Value: 1optional1.ifPresent( x -> System.out.println("Value: " + x));
私有接口方法
在 Java 8之前,接口可以有常量變量和抽象方法。
我們不能在接口中提供方法實現。如果我們要提供抽象方法和非抽象方法(方法與實現)的組合,那么我們就得使用抽象類。
在 Java 8 接口引入了一些新功能——默認方法和靜態方法。我們可以在Java SE 8的接口中編寫方法實現,僅僅需要使用?default?關鍵字來定義它們。
在 Java 8 中,一個接口中能定義如下幾種變量/方法:
- 常量
- 抽象方法
- 默認方法
- 靜態方法
Java 9 不僅像 Java 8 一樣支持接口默認方法,同時還支持私有方法。
在 Java 9 中,一個接口中能定義如下幾種變量/方法:
- 常量
- 抽象方法
- 默認方法
- 靜態方法
- 私有方法
- 私有靜態方法
public interface java9StudyInterface {// 默認方法default void process() {readData();analyzeData();writeResult();}// 私有工具方法(僅接口內部使用)private void readData() {System.out.println("讀取數據");}private void writeResult() {System.out.println("寫入結果");}// 抽象方法(由實現類提供)void analyzeData();
}
public class java9StudyClazz implements java9StudyInterface {@Overridepublic void analyzeData() {System.out.println("analyzeData");}
}
java9StudyInterface java9StudyClazz = new java9StudyClazz();java9StudyClazz.process();輸出:讀取數據analyzeData寫入結果