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写入结果