☕Java10新特性
|字数总计:2.2k|阅读时长:9分钟|阅读量:|
java10
于2018.3.21
发布,是一个non-LTS
版本,本文将介绍该版本带来的主要新特性。
java10
主要新特性一览
- 局部变量类型推断
- 容器类新增
copyOf
方法 Reader
类和InputStream
类中新增transferTo
方法IO
流类系添加带Charset
类参数的方法java.util.Optional
类新增重载的无参orElseThrow()
方法G1
引入并行full gc
- 删除
javah
工具
局部变量类型推断
长期以来,java
声明变量每次都要写两遍变量类型,第一次用于声明变量类型,第二次用于构造器。例如:
1
| ArrayList<String> list2 = new ArrayList<>();
|
再或者遇到返回值类型带复杂泛型结构时,变量类型的编写复杂且较长,例如:
1 2
| LinkedHashSet<Map.Entry<String, String>> set = new LinkedHashSet<>(); Iterator<Map.Entry<String, String>> iterator = set.iterator();
|
虽然我们可以直接忽略掉泛型Iterator i = set.iterator();
,但是这样编译器会报黄色警告,看着很不舒服。
java10
新增了var
语法来进行局部变量类型推断,在定义局部变量、接收复杂泛型结构返回值及for
循环中可以使用。其中在定义局部变量时必须立刻进行赋值,且等号右边的类型一定要明确;而且不能同时定义多个局部变量。具体使用示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package com.sunchaser.sparrow.javase.java10;
import java.util.*;
public class LocalVariableTypeInference { public static void main(String[] args) { ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<>();
LinkedHashSet<Map.Entry<String, String>> set = new LinkedHashSet<>(); Iterator<Map.Entry<String, String>> iterator = set.iterator();
var list3 = new ArrayList<Integer>(); var str = "var string"; var num = 1; var d = 1.0;
System.out.println(str); System.out.println(num); System.out.println(d);
var iter = set.iterator();
list2.add("java"); list2.add("go"); list2.add("python"); for (var s : list2) { System.out.println(s); System.out.println(s.getClass()); }
list3.add(1); list3.add(3); list3.add(5); for (var i = 0; i < list3.size(); i++) { System.out.println(list3.get(i)); System.out.println(list3.get(i).getClass()); } } }
|
本质上,var
只是一个语法糖,编译器在编译期进行类型推断,然后写入.class
字节码文件中。上述示例代码对应的字节码文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) //
package com.sunchaser.sparrow.javase.java10;
import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map.Entry;
public class LocalVariableTypeInference { public LocalVariableTypeInference() { }
public static void main(String[] args) { new ArrayList(); ArrayList<String> list2 = new ArrayList(); LinkedHashSet<Entry<String, String>> set = new LinkedHashSet(); Iterator<Entry<String, String>> iterator = set.iterator(); ArrayList<Integer> list3 = new ArrayList(); String str = "var string"; int num = 1; double d = 1.0D; System.out.println(str); System.out.println(num); System.out.println(d); Iterator<Entry<String, String>> iter = set.iterator(); list2.add("java"); list2.add("go"); list2.add("python"); Iterator var11 = list2.iterator();
while(var11.hasNext()) { String s = (String)var11.next(); System.out.println(s); System.out.println(s.getClass()); }
list3.add(1); list3.add(3); list3.add(5);
for(int i = 0; i < list3.size(); ++i) { System.out.println(list3.get(i)); System.out.println(((Integer)list3.get(i)).getClass()); }
} }
|
容器类新增copyOf
方法
java10
在List/Set/Map
容器接口中新增了一个copyOf
静态方法,该方法将一个容器复制为另一个新的不可变容器。
代码示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| package com.sunchaser.sparrow.javase.java10;
import java.util.*;
public class CollectionCopyOf { public static void main(String[] args) { copyOfList();
copyOfSet();
copyOfMap(); }
private static void copyOfMap() { Map<String, String> map = new HashMap<>(); map.put("java", "1"); map.put("python", "2"); map.put("go", "3"); Map<String, String> copyOfMap = Map.copyOf(map); for (Map.Entry<String, String> entry : copyOfMap.entrySet()) { System.out.println(entry.getKey()); System.out.println(entry.getValue()); } }
private static void copyOfSet() { Set<String> set = new HashSet<>(); set.add("java"); set.add("python"); set.add("go"); Set<String> copyOfSet = Set.copyOf(set); for (String s : copyOfSet) { System.out.println(s); } }
private static void copyOfList() { List<String> list = new ArrayList<>(); list.add("java"); list.add("python"); list.add("go"); List<String> copyOfList = List.copyOf(list); for (String s : copyOfList) { System.out.println(s); } } }
|
查看copyOf
源码可知,实际上内部调用的是java9
新增的of
方法得到一个不可变容器。例如List.copyOf()
源码如下:
1 2 3 4 5 6 7
| static <E> List<E> copyOf(Collection<? extends E> coll) { if (coll instanceof ImmutableCollections.AbstractImmutableList) { return (List<E>)coll; } else { return (List<E>)List.of(coll.toArray()); } }
|
java10
之前如果需要复制文件,需要自己定义数组,循环读取输入流并写到输出流中,代码比较麻烦:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private static final String FILE = Objects.requireNonNull(TransferTo.class.getResource("/")).getFile();
private static void copyFileBeforeJava10() { try { // 复制source.txt文件到target1.txt FileReader fr = new FileReader(FILE + "source.txt"); FileWriter fw = new FileWriter(FILE + "target1.txt"); char[] chs = new char[1024 * 8]; int len; while ((len = fr.read(chs)) != -1) { fw.write(chs, 0, len); } fr.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } }
|
java10
在InputStream
类和Reader
类中提供了transferTo
方法,将输入流读取的数据使用使用字符输出流写出。可用于快速实现文件复制操作。代码示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private static final String FILE = Objects.requireNonNull(TransferTo.class.getResource("/")).getFile();
private static void copyFileInJava10() { try { // 复制source.txt文件到target2.txt FileReader fr = new FileReader(FILE + "source.txt"); FileWriter fw = new FileWriter(FILE + "target2.txt");
fr.transferTo(fw);
fr.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } }
|
查看java.io.Reader#transferTo
方法源码如下:
1 2 3 4 5 6 7 8 9 10 11
| public long transferTo(Writer out) throws IOException { Objects.requireNonNull(out, "out"); long transferred = 0; char[] buffer = new char[TRANSFER_BUFFER_SIZE]; int nRead; while ((nRead = read(buffer, 0, TRANSFER_BUFFER_SIZE)) >= 0) { out.write(buffer, 0, nRead); transferred += nRead; } return transferred; }
|
实际上就是对之前版本写法的封装,更加方便开发者。
IO
流类系添加带Charset
类参数的方法
java10
中给PrintStream
、PrintWriter
及Scanner
等类添加了带java.nio.charset.Charset
参数的构造器,通过java.nio.charset.Charset
可以指定IO
流操作文件时的编码。
以PrintStream
往指定文件中写字符为例,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.sunchaser.sparrow.javase.java10;
import java.io.IOException; import java.io.PrintStream; import java.nio.charset.StandardCharsets;
public class IOCharset { public static void main(String[] args) { try { PrintStream ps = new PrintStream("/Users/sunchaser/workspace/idea-projects/sunchaser-sparrow/java-se/java10/src/main/resources/ps.txt", StandardCharsets.UTF_8); ps.println("io charset 参数"); ps.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
Tips
: Charset
是一个抽象类,我们无法直接创建其对象,可以使用java.nio.charset.StandardCharsets
类当中预定义好的常见一些编码格式,或者使用Charset.forName("编码")
静态方法得到其子类实例。
java.util.Optional
类新增重载的无参orElseThrow()
方法
java10
中新增了重载的无参orElseThrow()
方法,当value
非空时,返回value
;否则抛出NoSuchElementException("No value present")
异常。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.sunchaser.sparrow.javase.java10;
import java.util.Optional;
public class OptionalMethod { public static void main(String[] args) { Optional<Object> empty = Optional.empty(); Optional<String> op = Optional.of("java"); String elseThrow = op.orElseThrow(); System.out.println(elseThrow); } }
|
G1
引入并行full gc
G1
收集器是被设计用来避免虚拟机进行full gc
的,当并发收集器回收内存太慢时虚拟机就会进行一次full gc
。G1
收集器从java7
开始被引入,在java9
中是默认的垃圾回收器,但是此时G1
的full gc
采用的是单线程标记-清除-整理算法,比较影响性能。所以在java10
中,引入了并行标记-清除-整理算法,使用的线程数与Young
和Mixed
收集器一致,线程数量可以通过-XX:ParallelGCThreads
参数来配置,这也会影响Young
和Mixed
收集器使用的线程数。
删除javah
工具
javah
用于生成c
语言的头文件。从java8
开始,javah
的功能已经集成到javac
中,所以删除javah
工具。
1
| javac -h /path/ 文件名.java
|