前言
JDK 15發布啦~ 我們一起回顧JDK 5-15 的新特性吧,大家一起學習哈~
本文已經收錄到github
❝https://github.com/whx123/JavaHome
❞
「公眾號:撿田螺的小男孩」
Java 5 新特性

1. 泛型
泛型本質是參數化類型,解決不確定具體對象類型的問題。
List<String> strList=new ArrayList<String>();
2. 增強循環(for-each)
for-each循環簡化了集合的遍歷。
String [] str = {"關注","公眾號","撿田螺的小男孩"};
for (String temp:str) {
System.out.println(temp);
}
3. 自動封箱拆箱
-
自動裝箱: 就是將基本數據類型自動轉換成對應的包裝類。 -
自動拆箱:就是將包裝類自動轉換成對應的基本數據類型。
包裝類型有:Integer,Double,Float,Long,Short,Character和Boolean
Integer i =666; //自動裝箱
int a= i; //自動拆箱
4. 枚舉
關鍵字enum可以將一組具名的值的有限集合創建為一種新的類型,而這些具名的值可以作為常規的程序組件使用,這就是枚舉類型。
enum SeasonEnum {
SPRING,SUMMER,FALL,WINTER;
}
5. 可變參數
我們在定義方法參數的時候不確定定義多少個,就可以定義為「可變參數」,它本質上是一個「數組」。
public static void main(String[] args) throws Exception {
String [] str = {"關注","公眾號","撿田螺的小男孩"};
testVarargs(str);
String str1 = "關注公眾號,撿田螺的小男孩";
testVarargs(str1);
}
//可變參數String... args
private static void testVarargs(String... args) {
for (String arg : args) {
System.out.println(arg);
}
}
6. 注解
可以把注解理解為代碼里的特殊標記,這些標記可以在編譯,類加載,運行時被讀取,並執行相應的處理。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
7.靜態導入
通過import static類,就可以使用類里的靜態變量或方法。看一下例子哈~
import static java.lang.System.out; //靜態導入System類的靜態變量out
public class Test {
public static void main(String[] args) throws Exception {
String str1 = "關注公眾號,撿田螺的小男孩";
System.out.println(str1); //常規寫法
out.println(str1); //靜態導入,可以直接使用out輸出
}
}
8. 線程並發庫(JUC)
JDK5 豐富了線程處理功能,java.util.concurrent包提供了以下的類、接口:
❝❞
線程池:ExecutorService接口 線程護斥:Lock 類 線程通信:Condition接口 同步隊列:ArrayBlockingQueue類 同步集合:ConcurrentHashMap類
Java 6 新特性

1.Desktop類和SystemTray類
JDK 6在java.awt包下,新增了兩個類:Desktop類和SystemTray類
❝❞
「Desktop類」: 用來打開系統默認瀏覽器瀏覽指定的URL,打開系統默認郵件客戶端發郵件等 「SystemTray類」:用來在系統托盤區創建一個托盤程序,如果在微軟的Windows上,它被稱為“任務欄”狀態區域。
//獲取Desktop實例
Desktop desktop = Desktop.getDesktop();
desktop.browse(URI.create("https://www.baidu.com"));
2. 使用JAXB2來實現對象與XML之間的映射
JAXB,即Java Architecture for XML Binding,可以實現對象與XML之間的映射,常用注解如下:
❝❞
@XmlRootElement:注解在類上面,對應xml的跟元素,使用name屬性定義根節點的名稱。 @XmlElement:指定一個字段或get/set方法映射到xml的節點,使用name屬性定義這個根節點的名稱。 @XmlAttribute:將JavaBean對象的屬性映射為xml的屬性,使用name屬性為生成的xml屬性指定別名。 @XmlAccessorType:定義映射這個類中的何種類型都需要映射到xml。 @XmlSchema: 將包映射到XML名稱空間
「看個例子吧~」
public class JAXB2XmlTest {
public static void main(String[] args) throws JAXBException, IOException {
List<Singer> list = new ArrayList<>();
list.add(new Singer("jay", 8));
list.add(new Singer("eason", 10));
SingerList singerList = new SingerList();
singerList.setSingers(list);
String str = JAXB2XmlTest.beanToXml(singerList, SingerList.class);
String path = "C:\\jay.txt";
BufferedWriter bfw = new BufferedWriter(new FileWriter(new File(path)));
bfw.write(str);
bfw.close();
}
private static String beanToXml(Object obj, Class<?> load) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(load);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
}
}
public class Singer {
private String name;
private int age;
public Singer(String name, int age) {
this.name = name;
this.age = age;
}
@XmlAttribute(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute(name="age")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@XmlRootElement(name="list")
public class SingerList {
private List<Singer> singers;
@XmlElement(name="singer")
public List<Singer> getSingers() {
return singers;
}
public void setSingers(List<Singer> singers) {
this.singers = singers;
}
}
「運行效果:」
<?xml version="1.0" encoding="GBK" standalone="yes"?>
<list>
<singer age="8" name="jay"/>
<singer age="10" name="eason"/>
</list>
3.輕量級 Http Server API
JDK 6中提供了簡單的Http Server API,可以構建嵌入式Http服務器,同時支持Http和Https協議。HttpServer會調用HttpHandler實現類的回調方法來處理客戶端請求,這里用戶只需實現HttpHandler接口就可以了。
/**
* 根據Java提供的API實現Http服務器
*/
public class MyHttpServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//創建HttpServer服務器
HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), 10);
//將 /jay請求交給MyHandler處理器處理
httpServer.createContext("/", new MyHandler());
httpServer.start();
}
}
public class MyHandler implements HttpHandler {
public void handle(HttpExchange httpExchange) throws IOException {
//請求頭
Headers headers = httpExchange.getRequestHeaders();
Set<Map.Entry<String, List<String>>> entries = headers.entrySet();
StringBuffer response = new StringBuffer();
for (Map.Entry<String, List<String>> entry : entries){
response.append(entry.toString() + "\n");
}
//設置響應頭屬性及響應信息的長度
httpExchange.sendResponseHeaders(200, response.length());
//獲得輸出流
OutputStream os = httpExchange.getResponseBody();
os.write(response.toString().getBytes());
os.close();
}
}
4. 插入式注解處理API
❝JDK 6提供了插入式注解處理API,可以讓我們定義的注解在編譯期而不是運行期生效,從而可以在編譯期修改字節碼。lombok框架就是使用該特性來實現的,Lombok通過注解的方式,在編譯時自動為屬性生成構造器、getter/setter、equals、hashcode、toString等方法,大大簡化了代碼的開發。
❞
5. STAX
STAX,是JDK6中一種處理XML文檔的API。
public class STAXTest {
public static void main(String[] args) throws Exception {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader xmlEventReader = xmlInputFactory.createXMLEventReader(new FileInputStream("C:\\jay.xml"));
XMLEvent event = null;
StringBuffer stringBuffer = new StringBuffer();
while (xmlEventReader.hasNext()) {
event = xmlEventReader.nextEvent();
stringBuffer.append(event.toString());
}
System.out.println("xml文檔解析結果:");
System.out.println(stringBuffer);
}
}
「運行結果:」
xml文檔解析結果:
<?xml version="1.0" encoding='GBK' standalone='yes'?><list>
<singer name='jay' age='8'></singer>
<singer name='eason' age='10'></singer>
</list>ENDDOCUMENT
6. Common Annotations
❝Common annotations原本是Java EE 5.0(JSR 244)規范的一部分,現在SUN把它的一部分放到了Java SE 6.0中。隨着Annotation元數據功能加入到Java SE 5.0里面,很多Java 技術都會用Annotation部分代替XML文件來配置運行參數。
❞
以下列舉Common Annotations 1.0里面的幾個Annotations:
-
@Generated:用於標注生成的源代碼 -
@Resource: 用於標注所依賴的資源,容器據此注入外部資源依賴,有基於字段的注入和基於setter方法的注入兩種方式 。 -
@Resources:同時標注多個外部依賴,容器會把所有這些外部依賴注入 -
@PostConstruct:標注當容器注入所有依賴之后運行的方法,用來進行依賴注入后的初始化工作,只有一個方法可以標注為PostConstruct 。 -
@PreDestroy:當對象實例將要被從容器當中刪掉之前,要執行的回調方法要標注為PreDestroy
7. Compiler API
javac編譯器可以把.java的源文件編譯為.class文件,JDK 6的新特性Compiler API(JSR 199)也可以動態編譯Java源文件。
public class CompilerApiTest {
public static void main(String[] args) throws Exception {
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null,null,null);
Iterable<? extends JavaFileObject> javaFileObjects = standardJavaFileManager.getJavaFileObjects("C:\\Singer.java");
javaCompiler.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects).call();
standardJavaFileManager.close();
}
}
運行結果:會在C目錄生成Singer.class文件
8. 對腳本語言的支持(如: ruby, groovy, javascript)
JDK6增加了對腳本語言的支持(JSR 223),原理是將腳本語言編譯成字節碼,這樣腳本語言也能享用Java平台的諸多優勢,包括可移植性,安全等。JDK6實現包含了一個基於Mozilla Rhino的 腳本語言引擎,因此可以支持javascript,當然JDK也支持ruby等其他語言
public class JavaScriptTest {
public static void main(String[] args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
String script;
try {
script = "print('Hello')";
engine.eval(script);// 執行腳本
}catch (Exception e) {
e.printStackTrace();
}
}
}
//output
Hello
Java 7 新特性

1.switch 支持String字符串類型。
String singer = "jay";
switch (singer) {
case "jay" :
System.out.println("周傑倫");
break;
case "eason" :
System.out.println("陳奕迅");
break ;
default :
System.out.println("其他");
break ;
}
2.try-with-resources,資源自動關閉
JDK 7 之前:
BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt"));
try {
return br.readLine();
} finally {
br.close();
}
JDK 7 之后:
/*
* 聲明在try括號中的對象稱為資源,在方法執行完畢后會被自動關閉
*/
try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) {
return br.readLine();
}
3. 整數類型如(byte,short,int,long)能夠用二進制來表示
//0b或者0B表示二進制
int a = 0b010;
int b = 0B010;
4. 數字常量支持下划線
int a = 11_11;//a的值為1111,下划線不影響實際值,提升可讀性
5. 泛型實例化類型自動推斷,即”<>”
JDK 7 之前:
Map<String, List<String>> map = new HashMap<String, List<String>>();
JDK 7之后:
//不須聲明類型,自動根據前面<>推斷其類型
Map<String, List<String>> map = new HashMap<>();
6.一個catch中捕獲多個異常類型,用(|)分隔開
JDK 7之前
try{
//do something
} catch (FirstException e) {
logger.error(e);
} catch (SecondException e) {
logger.error(ex);
}
JDk 7之后
try{
//do something
} catch (FirstException | SecondException e) {
logger.error(e);
}
7. 增強的文件系統
Java7 提供了全新的NIO2.0 API,方便文件管理的編碼。如,可以在java.nio.file包下使用Path、Paths、Files、WatchService等常用類型。
Path path = Paths.get("C:\\jay\\七里香.txt"); //創建Path對象
byte[] bytes= Files.readAllBytes(path); //讀取文件
System.out.println(path.getFileName()); //獲取當前文件名稱
System.out.println(path.toAbsolutePath()); // 獲取文件絕對路徑
System.out.println(new String(bytes, "utf-8"));
8. Fork/join 框架
Java7提供的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終匯總每個小任務結果后得到大任務結果的框架。
Fork/join計算1-1000累加值:
public class ForkJoinPoolTest {
private static final Integer DURATION_VALUE = 100;
static class ForkJoinSubTask extends RecursiveTask<Integer>{
// 子任務開始計算的值
private Integer startValue;
// 子任務結束計算的值
private Integer endValue;
private ForkJoinSubTask(Integer startValue , Integer endValue) {
this.startValue = startValue;
this.endValue = endValue;
}
@Override
protected Integer compute() {
//小於一定值DURATION,才開始計算
if(endValue - startValue < DURATION_VALUE) {
System.out.println("執行子任務計算:開始值 = " + startValue + ";結束值 = " + endValue);
Integer totalValue = 0;
for (int index = this.startValue; index <= this.endValue; index++) {
totalValue += index;
}
return totalValue;
} else {
// 將任務拆分,拆分成兩個任務
ForkJoinSubTask subTask1 = new ForkJoinSubTask(startValue, (startValue + endValue) / 2);
subTask1.fork();
ForkJoinSubTask subTask2 = new ForkJoinSubTask((startValue + endValue) / 2 + 1 , endValue);
subTask2.fork();
return subTask1.join() + subTask2.join();
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Fork/Join框架的線程池
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Integer> taskFuture = pool.submit(new ForkJoinSubTask(1,1000));
Integer result = taskFuture.get();
System.out.println("累加結果是:" + result);
}
}
運行結果:
...
執行子任務計算:開始值 = 189;結束值 = 250
執行子任務計算:開始值 = 251;結束值 = 313
執行子任務計算:開始值 = 314;結束值 = 375
執行子任務計算:開始值 = 376;結束值 = 438
執行子任務計算:開始值 = 439;結束值 = 500
執行子任務計算:開始值 = 501;結束值 = 563
執行子任務計算:開始值 = 564;結束值 = 625
執行子任務計算:開始值 = 626;結束值 = 688
執行子任務計算:開始值 = 689;結束值 = 750
執行子任務計算:開始值 = 751;結束值 = 813
執行子任務計算:開始值 = 814;結束值 = 875
執行子任務計算:開始值 = 876;結束值 = 938
執行子任務計算:開始值 = 939;結束值 = 1000
累加結果是:500500
Java 8 新特性

1.lambada表達式
Lambda 允許把函數作為一個方法的參數,傳遞到方法中
語法格式:
(parameters) -> expression 或 (parameters) ->{ statements; }
代碼示例:
Arrays.asList("jay", "Eason", "SHE").forEach(
( String singer ) -> System.out.print( singer + ",") );
2. 函數式接口
Lambda的設計者為了讓現有的功能與Lambda表達式很好兼容,設計出函數式接口。
-
函數式接口是指只有一個函數的接口,可以隱式轉換為lambada表達式。 -
Java 8 提供了注解@FunctionalInterface,顯示聲明一個函數式接口。 -
java.lang.Runnable和java.util.concurrent.Callable是函數式接口的例子~
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
3. 方法引用
方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。它與Lambda表達式配合使用,可以減少冗余代碼,使代碼更加簡潔。
//利用函數式接口Consumer的accept方法實現打印,Lambda表達式如下
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("jay");
//引用PrintStream類(也就是System.out的類型)的println方法,這就是方法引用
consumer = System.out::println;
consumer.accept("關注公眾號撿田螺的小男孩");
4. 默認方法
默認方法就是一個在接口里面有了一個實現的方法。它允許將新方法添加到接口,但不強制實現了該接口的類必須實現新的方法。
public interface ISingerService {
// 默認方法
default void sing(){
System.out.println("唱歌");
}
void writeSong();
}
//JaySingerServiceImpl 不用強制實現ISingerService的默認sing()方法
public class JaySingerServiceImpl implements ISingerService {
@Override
public void writeSong() {
System.out.println("寫了一首七里香");
}
}
5.Stream API
Stream API,支持對元素流進行函數式操作,它集成在Collections API 中,可以對集合進行批量操作。常用API:
-
filter 篩選 -
map流映射 -
reduce 將流中的元素組合起來 -
collect 返回集合 -
sorted 排序 -
flatMap 流轉換 -
limit返回指定流個數 -
distinct去除重復元素
public class Singer {
private String name;
private Integer songNum;
private Integer age;
...
}
List<Singer> singerList = new ArrayList<Singer>();
singerList.add(new Singer("jay", 11, 36));
singerList.add(new Singer("eason", 8, 31));
singerList.add(new Singer("JJ", 6, 29));
List<String> singerNameList = singerList.stream()
.filter(singer -> singer.getAge() > 30) //篩選年齡大於30
.sorted(Comparator.comparing(Singer::getSongNum)) //根據歌曲數量排序
.map(Singer::getName) //提取歌手名字
.collect(Collectors.toList()); //轉換為List
6. Optional
Java 8引入Optional類,用來解決NullPointerException。Optional代替if...else解決空指針問題,使代碼更加簡潔。
if...else 判空
Singer singer = getSingerById("666");
if (singer != null) {
String name = singer.getName();
System.out.println(name);
}
Optional的判空
Optional<Singer> singer = Optional.ofNullable(getSingerById("666"));
singer.ifPresent(s -> System.out.println(s.getName()));
7. Date Time API
JDK 8之前的日期API處理存在非線程安全、時區處理麻煩等問題。Java 8 在 java.time包下提供了新的日期API,簡化了日期的處理~
LocalDate today = LocalDate.now();
int year = today.getYear();
System.out.println("今年是" + year);
//是否閏年
System.out.println("今年是不是閏年:" + today.isLeapYear());
LocalDateTime todayTime = LocalDateTime.now();
System.out.println("當前時間" + todayTime);
//時區指定
System.out.println("美國時間:" + ZonedDateTime.of(todayTime,ZoneId.of("America/Los_Angeles")));
LocalDate specailDate = LocalDate.of(2020, 6, 20);
LocalDate expectDate = specailDate.plus(100, ChronoUnit.DAYS);
System.out.println("比較特別的一天" + specailDate);
System.out.println("特殊日期的100天" + expectDate);
8. 重復注解
重復注解,即一個注解可以在一個類、屬性或者方法上同時使用多次;用@Repeatable定義重復注解
@Repeatable(ScheduleTimes.class)
public @interface ScheduleTime {
String value();
}
public @interface ScheduleTimes {
ScheduleTime[] value();
}
public class ScheduleTimeTask {
@ScheduleTime("10")
@ScheduleTime("12")
public void doSomething() { }
}
9. Base64
Java 8把Base64編碼的支持加入到官方庫中~
String str = "公眾號:撿田螺的小男孩";
String encoded = Base64.getEncoder().encodeToString(str.getBytes( StandardCharsets.UTF_8));
String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
10. JVM的新特性
使用元空間Metaspace代替持久代(PermGen space),JVM參數使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize設置大小。
Java 9 新特性

1. java模塊系統
什么是模塊化?
❝一個大型系統,比如一個商城網站,它會包含很多模塊的,如:訂單模塊,用戶信息模塊,商品信息模塊,廣告位模塊等等。各個模塊之間會相互調用。如果每個模塊單獨運行都會帶動其他所有模塊,性能非常低效。但是,如果某一模塊運行時,只會啟動它所依賴的模塊,性能大大提升。這就是JDK 9模塊化的思想。
❞
什么是JDK 9模塊化?
❝Java 平台模塊系統,即Project Jigsaw,把模塊化開發實踐引入到了Java平台中。在引入了模塊系統之后,JDK 被重新組織成94個模塊。Java 應用可以通過新增的jlink 工具,創建出只包含所依賴的JDK模塊的自定義運行時鏡像。這樣可以極大的減少Java運行時環境的大小。
❞
Java 9 模塊的重要特征:
❝❞
在其工件(artifact)的根目錄中包含了一個描述模塊的 module-info.class 文 件。 工件的格式可以是傳統的 JAR 文件或是 Java 9 新增的 JMOD 文件。 這個文件由根目錄中的源代碼文件 module-info.java 編譯而來。 該模塊聲明文件可以描述模塊的不同特征。
在 module-info.java 文件中,我們可以用新的關鍵詞module來聲明一個模塊,如下所示。下面給出了一個模塊com.mycompany.mymodule的最基本的模塊聲明
module com.jay.sample { //關鍵詞module來聲明一個模塊
exports com.jay.sample; //使用 exports可以聲明模塊對其他模塊所導出的包。
requires com.jay.common; //使用requires可以聲明模塊對其他模塊的依賴關系。
}
2. 不可變集合工廠方法
為了創建不可變集合,JDK9之前醬紫的:
List<String> stringList = new ArrayList<>();
stringList.add("關注公眾號:");
stringList.add("撿田螺的小男孩");
List<String> unmodifiableList = Collections.unmodifiableList(stringList);
JDK 9 提供了List.of()、Set.of()、Map.of()和Map.ofEntries()等工廠方法來創建不可變集合:
List<String> unmodifiableList = List.of("關注公眾號:","撿田螺的小男孩");
3. 接口支持私有方法
JDK 8支持在接口實現默認方法和靜態方法,但是不能在接口中創建私有方法,為了避免了代碼冗余和提高閱讀性,JDK 9在接口中支持私有方法。
public interface IPrivateInterfaceTest {
//JDK 7 之前
String a = "jay";
void method7();
//JDK 8
default void methodDefault8(){
System.out.println("JDK 8新特性默認方法");
}
static void methodStatic8() {
System.out.println("JDk 8新特性靜態方法");
}
//Java 9 接口支持私有方法
private void method9(){}
}
4. 鑽石操作符升級
-
鑽石操作符是在 java 7 中引入的,可以讓代碼更易讀,但它不能用於匿名的內部類。 -
在 java 9 中, 它可以與匿名的內部類一起使用,從而提高代碼的可讀性。
//JDK 5,6
Map<String, String> map56 = new HashMap<String,String>();
//JDk 7,8
Map<String, String> map78 = new HashMap<>();
//JDK 9 結合匿名內部類的實現
Map<String, String> map9 = new HashMap<>(){};
5. Optional 類改進
java 9 中,java.util.Optional 添加了很多新的有用方法,如:
-
stream() -
ifPresentOrElse() -
or()
ifPresentOrElse 方法的改進就是有了 else,接受兩個參數 Consumer 和 Runnable。
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
optional = Optional.empty();
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
}
}
6. 多版本兼容Jar包
❝很多公司使用的JDK都是老版本的,JDK6、JDk5 ,甚至JDk4的,不是他們不想升級JDk版本,而是擔心兼容性問題。JDK 9的一個新特性,多版本兼容Jar包解決了這個問題。舉個例子:假設你一直用的是小米8,已經非常習慣它的運行流程了,突然出來小米9,即使小米9很多新功能引人入勝,但是有些人不會輕易買小米9,因為已經已經習慣小米8的流程。同理,為什么很多公司不升級JDK,就是在此。但是呢,JDK 9的這個功能很強大,它可以讓你的版本升級到JDK 9,但是還是老版本的運行流程,即在老的運行流程繼承新的功能~
❞
7. JShell工具
jShell工具相當於cmd工具,然后呢,你可以像在cmd工具操作一樣,直接在上面運行Java方法,Java語句等~
jshell> System.out.println("關注公眾號:撿田螺的小男孩");
關注公眾號:撿田螺的小男孩
8. try-with-resources的改進
JDK 9對try-with-resources異常處理機制進行了升級~
//JDK 7,8
try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) {
br.readLine();
}catch(IOException e){
log.error("IO 異常,e:{}",e);
}
//JDk 9
BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")
try(br){
br.readLine();
}catch(IOException e){
log.error("IO 異常,e:{}",e);
}
9. Stream API的改進
JDK 9 為Stream API引入以下這些方法,豐富了流處理操作:
-
takeWhile() -
dropWhile() -
iterate -
ofNullable
「takeWhile」
使用一個斷言(Predicate 接口)作為參數,返回給定Stream的子集直到斷言語句第一次返回 false
// 語法格式
default Stream<T> takeWhile(Predicate<? super T> predicate)
//代碼示例
Stream.of(1,2,3).takeWhile(s-> x<2)
.forEach(System.out::println);
//輸出
1
「dropWhile」
與 takeWhile()作用相反,使用一個斷言(Predicate 接口)作為參數,直到斷言語句第一次返回true,返回給定Stream的子集
//語法
default Stream<T> dropWhile(Predicate<? super T> predicate)
//代碼示例
Stream.of(1,2,3).dropWhile(s-> x<2)
.forEach(System.out::println);
//輸出
2
3
「iterate」
iterate() 方法能夠返回以seed(第一個參數)開頭,匹配 Predicate(第二個參數)直到返回false,並使用第三個參數生成下一個元素的元素流。
//語法
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
//代碼示例
IntStream.iterate(2, x -> x < 10, x -> x*x).forEach(System.out::println);
//輸出
2
4
「ofNullable」
如果指定元素為非null,則獲取一個元素並生成單個元素流,元素為null則返回一個空Stream。
//語法
static <T> Stream<T> ofNullable(T t)
//代碼示例
Stream<Integer> s1= Stream.ofNullable(100);
s1.forEach(System.out::println)
Stream<Integer> s2 = Stream.ofNullable(null);
s2.forEach(System.out::println)
//輸出
100
10.其他
❝❞
HTTP 2客戶端 (支持 WebSocket和 HTTP2 流以及服務器推送) 進程API(控制和管理操作系統進程) String底層存儲結構更改(char[]替換為byte[]) 標識符添加限制( String _ ="hello"不能用) 響應式流 API (支持Java 9中的響應式編程)
Java 10 新特性

1.局部變量類型推斷
JDK 10增加了局部變量類型推斷(Local-Variable Type Inference)功能,讓 Java 可以像Js里的var一樣可以自動推斷數據類型。Java中的var是一個保留類型名稱,而不是關鍵字。
JDK 10之前
List<String> list = new ArrayList<String>();
Stream<Integer> stream = Stream.of(1, 2, 3);
JDK 10 之后
var list = new ArrayList<String>(); // ArrayList<String>
var stream = Stream.of(1, 2, 3);
var 變量類型推斷的使用也有局限性,僅「局限」於以下場景:
-
具有初始化器的局部變量 -
增強型for循環中的索引變量 -
傳統for循環中聲明的局部變量
而「不能用於」
-
推斷方法的參數類型 -
構造函數參數類型推斷 -
推斷方法返回類型 -
字段類型推斷 -
捕獲表達式
2. 不可變集合的改進
JDK 10中,List,Set,Map 提供了一個新的靜態方法copyOf(Collection<? extends E> coll),它返回Collection集合一個不可修改的副本。
JDK 源碼:
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
使用實例:
var oldList = new ArrayList<String>();
oldList.add("歡迎關注公眾號:");
oldList.add("撿田螺的小男孩");
var copyList = List.copyOf(oldList);
oldList.add("在看、轉載、點贊三連");
copyList.add("雙擊666"); //UnsupportedOperationException異常
3. 並行全垃圾回收器 G1
❝JDK 9引入 G1 作為默認垃圾收集器,執行GC 時采用的是基於單線程標記掃描壓縮算法(mark-sweep-compact)。為了最大限度地減少 Full GC 造成的應用停頓的影響,Java 10 中將為 G1 引入多線程並行 GC,同時會使用與年輕代回收和混合回收相同的並行工作線程數量,從而減少了 Full GC 的發生,以帶來更好的性能提升、更大的吞吐量。
❞
4. 線程本地握手
Java 10 中線程管控引入JVM安全點的概念,將允許在不運行全局JVM安全點的情況下實現線程回調,由線程本身或者JVM線程來執行,同時保持線程處於阻塞狀態,這將會很方便使得停止單個線程或不停止線程成為可能。
5. Optional新增orElseThrow()方法
Optional、OptionalDouble等類新增一個方法orElseThrow(),在沒有值時拋出異常
6. 其他新特性
-
基於 Java 的 實驗性 JIT 編譯器 -
類數據共享 -
Unicode 語言標簽擴展 -
根證書 -
基於時間(Time-Based)的版本控制模型
Java 11 新特性

1.字符串操作
String類是Java最常用的類,JDK 11增加了一系列好用的字符串處理方法
-
isBlank() 判空。 -
strip() 去除首尾空格 -
stripLeading() 去除字符串首部空格 -
stripTrailing() 去除字符串尾部空格 -
lines() 分割獲取字符串流。 -
repeat() 復制字符串
// 判斷字符串是否為空白
" ".isBlank(); // true
// 去除首尾空格
" jay ".strip(); // "jay"
// 去除首部空格
" jay ".stripLeading(); // "jay "
去除字符串尾部空格
" jay ".stripLeading(); // " jay"
// 行數統計
"a\nb\nc".lines().count(); // 3
// 復制字符串
"jay".repeat(3); // "jayjayjay"
2.用於 Lambda 參數的局部變量語法
局部變量類型推斷是Java 10引入的新特性,但是不能在Lambda 表達式中使用。Java 11再次創新,它允許開發者在 Lambda 表達式中使用 var 進行參數聲明。
var map = new HashMap<String, Object>();
map.put("公眾號", "撿田螺的小男孩");
map.forEach((var k, var v) -> {
System.out.println(k + ": " + v);
});
3.標准化HTTP Client
Java 9 引入Http Client API,Java 10對它更新,Java 11 對它進行標准化。這幾個版本后,Http Client幾乎被完全重寫,支持HTTP/1.1和HTTP/2 ,也支持 websockets。
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://github.com/whx123/JavaHome"))
.GET()
.build();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 異步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
4. 單個命令編譯運行源代碼
Java 11增強了Java 啟動器,使之能夠運行單一文件的Java 源代碼。
-
Java 11之前,要運行一個 Java 源代碼必須先編譯,再運行
// 編譯
javac Jay.java
// 運行
java Jay
-
Java 11之后,只要一個java命令就搞定
java Jay.java
5. ZGC:可伸縮低延遲垃圾收集器
ZGC ,即 Z Garbage Collector(垃圾收集器或垃圾回收器)。它是一個可伸縮的、低延遲的垃圾收集器。 ZGC 主要為了滿足如下目標進行設計:
-
GC 停頓時間不超過 10ms -
既能處理幾百 MB 的小堆,也能處理幾個 TB 的大堆 -
應用吞吐能力不會下降超過 15%(與 G1 回收算法相比) -
方便在此基礎上引入新的 GC 特性和利用 colord -
針以及 Load barriers 優化奠定基礎 -
當前只支持 Linux/x64 位平台
6.其他一些特性
-
添加 Epsilon 垃圾收集器。 -
支持 TLS 1.3 協議 -
飛行記錄器分析工具 -
動態類文件常量 -
低開銷的 Heap Profiling
Java 12 新特性

1. Switch 表達式擴展(預覽功能)
傳統的switch語句,容易漏寫break而出錯,同時寫法並不簡潔優雅。
Java 12之前
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
JDk 12 之后,Switch表達式得到增強,能接受語句和表達式。
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
2. 緊湊的數據格式
JDK 12 新增了NumberFormat對復雜數字的格式化
NumberFormat numberFormat = NumberFormat.getCompactNumberInstance(Locale.CHINA, NumberFormat.Style.SHORT);
System.out.println(numberFormat.format(100000));
//output
10萬
3. 字符串支持transform、indent操作
-
transform 字符串轉換,可以配合函數式接口Function一起使用
List<String> list1 = List.of("jay", " 撿田螺的小男孩");
List<String> list2 = new ArrayList<>();
list1.forEach(element ->
list2.add(element.transform(String::strip)
.transform((e) -> "Hello," + e))
);
list2.forEach(System.out::println);
//輸出
Hello,jay
Hello,撿田螺的小男孩
-
indent 縮進,每行開頭增加空格space和移除空格
String result = "Java\n Python\nC".indent(3);
System.out.println(result);
//輸出
Java
Python
C
4. Files.mismatch(Path, Path)
Java 12 新增了mismatch方法,此方法返回第一個不匹配的位置,如果沒有不匹配,則返回 -1L。
public static long mismatch(Path path, Path path2) throws IOException;
代碼示例:
Path file1 = Paths.get("c:\\jay.txt");
Path file2 = Paths.get("c:\\撿田螺的小男孩.txt");
try {
long fileMismatch = Files.mismatch(file1, file2);
System.out.println(fileMismatch);
} catch (IOException e) {
e.printStackTrace();
}
5. Teeing Collector
Teeing Collector 是 Streams API 中引入的新的收集器實用程序,它的作用是 merge 兩個 collector 的結果,API格式如下:
public static <T, R1, R2, R>
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger)
直接看代碼例子吧,如下為求學生的平均分和總分的例子
List<Student> studentList= Arrays.asList(
new Student("jay", 90),
new Student("撿田螺的小男孩", 100),
new Student("撿表情的小男孩", 80)
);
String teeingResult=studentList.stream().collect(
Collectors.teeing(
Collectors.averagingInt(Student::getScore),
Collectors.summingInt(Student::getScore),
(s1,s2)-> s1+ ":"+ s2
)
);
System.out.println(teeingResult); //90:270
6.其他特性
-
支持unicode 11(684個新字符、11個新blocks、7個新腳本) -
JVM 常量 API (主要在新的java.lang.invoke.constant包中定義了一系列基於值的符號引用類型,能夠描述每種可加載常量。) -
Shenandoah GC(低暫停時間垃圾收集器) -
G1 收集器提升 (可中止的混合收集集合、及時返回未使用的已分配內存) -
默認CDS檔案 -
JMH 基准測試
Java 13 新特性

Switch 表達式擴展(引入 yield 關鍵字)
傳統的switch:
private static String getText(int number) {
String result = "";
switch (number) {
case 1, 2:
result = "one or two";
break;
case 3:
result = "three";
break;
case 4, 5, 6:
result = "four or five or six";
break;
default:
result = "unknown";
break;
Java 13之后,value break 語句不再被編譯,而是用 yield 來進行值返回
private static String getText(int number) {
return switch (number) {
case 1, 2:
yield "one or two";
case 3:
yield "three";
case 4, 5, 6:
yield "four or five or six";
default:
yield "unknown";
};
}
2.文本塊升級
Java 13之前,字符串不能夠多行使用,需要通過換行轉義或者換行連接符等等,反正就是好麻煩、好難維護。
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, 撿田螺的小男孩</p>\n" +
" </body>\n" +
"</html>\n";
Java 13之后,清爽多了~
String html = """
<html>
<body>
<p>Hello, 撿田螺的小男孩</p>
</body>
</html>
""";
3. SocketAPI 重構
-
傳統的Java Socket API(java.net.ServerSocket 和 java.net.Socket)依賴於SocketImpl 的內部實現 -
在 Java 13之前,通過使用 PlainSocketImpl 作為 SocketImpl 的具體實現。 -
Java 13 中的新底層實現,引入 NioSocketImpl 的實現用以替換 SocketImpl 的 PlainSocketImpl 實現,此實現與 NIO(新 I/O)實現共享相同的內部基礎結構,並且與現有的緩沖區高速緩存機制集成在一起。
一個Socket簡單例子:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketAPITest {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8080)){
boolean runFlag = true;
while(runFlag){
Socket clientSocket = serverSocket.accept();
//搞事情
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行以上的實例,看下是否有以下關鍵詞輸出~
[class,load] sun.nio.ch.NioSocketImpl
4.FileSystems.newFileSystem新方法
FileSystems 類中添加了以下三種新方法,以便更容易地使用將文件內容視為文件系統的文件系統提供程序:
-
1、newFileSystem(Path) -
2、newFileSystem(Path, Map<String, ?>) -
3、newFileSystem(Path, Map<String, ?>, ClassLoader)
5. 增強 ZGC 釋放未使用內存
-
ZGC 是Java 11 中引入的最為矚目的垃圾回收特性,是一種可伸縮、低延遲的垃圾收集器。但是實際使用中,它不能夠主動將未使用的內存釋放給操作系統。 -
Java 13 中對 ZGC 的改進,包括釋放未使用內存給操作系統、支持最大堆大小為 16TB、JVM參數-XX:SoftMaxHeapSize 來軟限制堆大小
6.其他特性
-
動態 CDS 存檔, 擴展了 Java 10 中引入的類數據共享功能, 使用CDS 存檔變得更容易。 -
文本塊的字符串類新方法,如formatted(Object…args),stripIndent()等。
Java 14 新特性

1. instanceof模式匹配
instanceof 傳統使用方式:
if (person instanceof Singer) {
Singer singer = (Singer) person;
singer.sing();
} else if (person instanceof Writer) {
Writer writer = (Writer) person;
writer.write();
}
Java 14 對 instanceof 進行模式匹配改進之后
if (person instanceof Singer singer) {
singer.sing();
} else if (person instanceof Writer writer) {
writer.write();
}
2.Record 類型(預覽功能)
Java 14將Record 類型作為預覽特性而引入,有點類似於Lombok 的@Data注解,看個例子吧:
public record Person(String name, int age) {
public static String address;
public String getName() {
return name;
}
}
反編譯結果:
public final class Person extends java.lang.Record {
private final java.lang.String name;
private final java.lang.String age;
public Person(java.lang.String name, java.lang.String age) { /* compiled code */ }
public java.lang.String getName() { /* compiled code */ }
public java.lang.String toString() { /* compiled code */ }
public final int hashCode() { /* compiled code */ }
public final boolean equals(java.lang.Object o) { /* compiled code */ }
public java.lang.String name() { /* compiled code */ }
public java.lang.String age() { /* compiled code */ }
}
可以發現,當用 Record 來聲明一個類時,該類將自動擁有下面特征:
-
構造方法 -
hashCode() 方法 -
euqals() 方法 -
toString() 方法 -
類對象被final 關鍵字修飾,不能被繼承。
3. Switch 表達式-標准化
switch 表達式在之前的 Java 12 和 Java 13 中都是處於預覽階段,終於在 Java 14 標准化,成為穩定版本。
-
Java 12 為switch 表達式引入Lambda 語法 -
Java 13 使用yield代替 break 關鍵字來返回表達式的返回值。
String result = switch (day) {
case "M", "W", "F" -> "MWF";
case "T", "TH", "S" -> "TTS";
default -> {
if (day.isEmpty()) {
yield "Please insert a valid day.";
} else {
yield "Looks like a Sunday.";
}
}
};
System.out.println(result);
4. 改進 NullPointerExceptions提示信息
Java 14 之前:
String name = song.getSinger().getSingerName()
//堆棧信息
Exception in thread "main" java.lang.NullPointerException
at NullPointerExample.main(NullPointerTest.java:6)
Java 14,通過引入JVM 參數-XX:+ShowCodeDetailsInExceptionMessages,可以在空指針異常中獲取更為詳細的調用信息。
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Singer.getSingerName()"
because the return value of "rainRow.getSinger()" is null
at NullPointerExample.main(NullPointerTest.java:6)
5. 其他特性
-
G1 的 NUMA 可識別內存分配 -
刪除 CMS 垃圾回收器 -
GC 支持 MacOS 和 Windows 系統
Java 15 新特性
1.EdDSA 數字簽名算法
-
使用 Edwards-Curve 數字簽名算法(EdDSA)實現加密簽名。 -
與其它簽名方案相比,EdDSA 具有更高的安全性和性能。 -
得到許多其它加密庫(如 OpenSSL、BoringSSL)的支持。
2.Sealed Classes(封閉類,預覽)
封閉類,可以是封閉類、封閉接口,防止其他類或接口擴展或實現它們。
public abstract sealed class Singer
permits Jay, Eason{
...
}
類Singer被sealed 修飾,是封閉類,只能被2個指定子類(Jay, Eason)繼承。
3. Hidden Classes(隱藏類)
-
隱藏類天生為框架設計的。 -
隱藏類只能通過反射訪問,不能直接被其他類的字節碼。
4. Remove the Nashorn JavaScript Engine
-
Nashorn太難維護了,移除 Nashorn JavaScript引擎成為一種必然 -
其實早在JDK 11 中就已經被標記為 deprecated 了。
5.Reimplement the Legacy DatagramSocket API(重新實現DatagramSocket API)
-
重新實現老的DatagramSocket API -
更改java.net.DatagramSocket 和 java.net.MulticastSocket 為更加簡單、現代化的底層實現。
6.其他
-
Disable and Deprecate Biased Locking(准備禁用偏向鎖) -
instanceof 自動匹配模式(預覽) -
ZGC,一個可伸縮、低延遲的垃圾回收器。(轉正) -
Text Blocks,文本功能轉正(JDK 13和14預覽,14終於轉正) -
Remove the Solaris and SPARC Ports(刪除 Solaris 和 SPARC 端口) -
外部存儲器訪問 API(允許Java 應用程序安全有效地訪問 Java 堆之外的外部內存。) -
Record類型二次預覽(在Java 14就預覽過啦)
參考與感謝
-
JDK6 新特性 [1] -
Java 7的新功能 [2] -
Java 9 新特性概述 [3] -
Java 9 新特性 [4] -
Java 10 新特性介紹 [5] -
Java 11 新特性介紹 [6] -
Java 13 新特性概述 [7] -
Java 14 新特性概述 [8] -
JDK/Java 15發布 -
Java 15 正式發布, 14 個新特性,刷新你的認知!!
個人公眾號

Reference
JDK6 新特性: https://blog.csdn.net/weixin_40926603/article/details/84970283
[2]Java 7的新功能: https://stackoverflow.com/questions/213958/new-features-in-java-7
[3]Java 9 新特性概述: https://developer.ibm.com/zh/articles/the-new-features-of-Java-9/
[4]Java 9 新特性: https://www.runoob.com/java/java9-new-features.html
[5]Java 10 新特性介紹: https://developer.ibm.com/zh/technologies/java/articles/the-new-features-of-java-10/
[6]Java 11 新特性介紹: https://developer.ibm.com/zh/technologies/java/articles/the-new-features-of-java-11/
[7]Java 13 新特性概述: https://developer.ibm.com/zh/technologies/java/articles/the-new-features-of-java-13/
[8]Java 14 新特性概述: https://developer.ibm.com/zh/technologies/java/articles/the-new-features-of-java-14/