講師:尚硅谷-宋紅康(江湖人稱:康師傅)
官網:http://www.atguigu.com
新的語法結構,為我們勾勒出了 Java 語法進化的一個趨勢,將開發者從復雜、繁瑣的低層次抽象中逐漸解放出來,以更高層次、更優雅的抽象,既降低代碼量,又避免意外編程錯誤的出現,進而提高代碼質量和開發效率。
JDK9的新特性
Java 終于擁有了像Python 和 Scala 之類語言的REPL工具(交互式編程環境,read - evaluate - print - loop):jShell。以交互式的方式對語句和表達式進行求值。即寫即得、快速運行。
利用jShell在沒有創建類的情況下,在命令行里直接聲明變量,計算表達式,執行語句。無需跟人解釋”public static void main(String[] args)”這句"廢話"。
使用舉例
調出jShell
??
獲取幫助
??
基本使用
??
導入指定的包
??
默認已經導入如下的所有包:(包含java.lang包)
??
只需按下 Tab 鍵,就能自動補全代碼
??
列出當前 session 里所有有效的代碼片段
?
?
查看當前 session 下所有創建過的變量
??
查看當前 session 下所有創建過的方法
?
?
Tips:我們還可以重新定義相同方法名和參數列表的方法,即對現有方法的修改(或覆蓋)。
使用外部代碼編輯器來編寫 Java 代碼
?
從外部文件加載源代碼【HelloWorld.java】
/** * Created by songhongkang */ public void printHello() { ? ?System.out.println("馬上2023年了,尚硅谷祝所有的谷粉元旦快樂!"); } printHello(); ?使用/open命令調用
??
退出jShell
??
在JDK7 之前,我們這樣處理資源的關閉:
@Test public void test01() { ? ?FileWriter fw = null; ? ?BufferedWriter bw = null; ? ?try { ? ? ? ?fw = new FileWriter("d:/1.txt"); ? ? ? ?bw = new BufferedWriter(fw); ? ? ? ? ?bw.write("hello"); ? } catch (IOException e) { ? ? ? ?e.printStackTrace(); ? } finally { ? ? ? ?try { ? ? ? ? ? ?if (bw != null) { ? ? ? ? ? ? ? ?bw.close(); ? ? ? ? ? } ? ? ? } catch (IOException e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } ? ? ? ?try { ? ? ? ? ? ?if (fw != null) { ? ? ? ? ? ? ? ?fw.close(); ? ? ? ? ? } ? ? ? } catch (IOException e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } ? ? } }JDK7的新特性
在try的后面可以增加一個(),在括號中可以聲明流對象并初始化。try中的代碼執行完畢,會自動把流對象釋放,就不用寫finally了。
格式:
try(資源對象的聲明和初始化){ ? ?業務邏輯代碼,可能會產生異常 }catch(異常類型1 e){ ? ?處理異常代碼 }catch(異常類型2 e){ ? ?處理異常代碼 }說明:
1、在try()中聲明的資源,無論是否發生異常,無論是否處理異常,都會自動關閉資源對象,不用手動關閉了。
2、這些資源實現類必須實現AutoCloseable或Closeable接口,實現其中的close()方法。Closeable是AutoCloseable的子接口。Java7幾乎把所有的“資源類”(包括文件IO的各種類、JDBC編程的Connection、Statement等接口…)都進行了改寫,改寫后資源類都實現了AutoCloseable或Closeable接口,并實現了close()方法。
3、寫到try()中的資源類的變量默認是final聲明的,不能修改。
舉例:
//舉例1 @Test public void test02() { ? ?try ( ? ? ? ?FileWriter fw = new FileWriter("d:/1.txt"); ? ? ? ?BufferedWriter bw = new BufferedWriter(fw); ? ) { ? ? ? ?bw.write("hello"); ? } catch (IOException e) { ? ? ? ?e.printStackTrace(); ? } } ? //舉例2 @Test public void test03() { ? ?//從d:/1.txt(utf-8)文件中,讀取內容,寫到項目根目錄下1.txt(gbk)文件中 ? ?try ( ? ? ? ?FileInputStream fis = new FileInputStream("d:/1.txt"); ? ? ? ?InputStreamReader isr = new InputStreamReader(fis, "utf-8"); ? ? ? ?BufferedReader br = new BufferedReader(isr); ? ? ? ? ?FileOutputStream fos = new FileOutputStream("1.txt"); ? ? ? ?OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk"); ? ? ? ?BufferedWriter bw = new BufferedWriter(osw); ? ) { ? ? ? ?String str; ? ? ? ?while ((str = br.readLine()) != null) { ? ? ? ? ? ?bw.write(str); ? ? ? ? ? ?bw.newLine(); ? ? ? } ? } catch (FileNotFoundException e) { ? ? ? ?e.printStackTrace(); ? } catch (IOException e) { ? ? ? ?e.printStackTrace(); ? } }JDK9的新特性
try的前面可以定義流對象,try后面的()中可以直接引用流對象的名稱。在try代碼執行完畢后,流對象也可以釋放掉,也不用寫finally了。
格式:
A a = new A(); B b = new B(); try(a;b){ ? ?可能產生的異常代碼 }catch(異常類名 變量名){ ? ?異常處理的邏輯 }舉例:
@Test public void test04() { ? ?InputStreamReader reader = new InputStreamReader(System.in); ? ?OutputStreamWriter writer = new OutputStreamWriter(System.out); ? ?try (reader; writer) { ? ? ? ?//reader是final的,不可再被賦值 ? ? ? ?// ? reader = null; ? ? } catch (IOException e) { ? ? ? ?e.printStackTrace(); ? } }JDK 10的新特性
局部變量的顯示類型聲明,常常被認為是不必須的,給一個好聽的名字反而可以很清楚的表達出下面應該怎樣繼續。本新特性允許開發人員省略通常不必要的局部變量類型聲明,以增強Java語言的體驗性、可讀性。
使用舉例
不適用場景
聲明一個成員變量
聲明一個數組變量,并為數組靜態初始化(省略new的情況下)
方法的返回值類型
方法的參數類型
沒有初始化的方法內的局部變量聲明
作為catch塊中異常類型
Lambda表達式中函數式接口的類型
方法引用中函數式接口的類型
代碼舉例:
聲明一個成員變量,并初始化值為null
??
聲明一個數組變量,并為數組靜態初始化(省略new的情況下)
??
沒有初始化的方法內的局部變量聲明
???
方法的返回值類型
?
方法的參數類型
?
構造器的參數類型
?
作為catch塊中異常類型
?
Lambda表達式中函數式接口的類型
?
方法引用中函數式接口的類型
?
注意:
var不是一個關鍵字,而是一個類型名,將它作為變量的類型。不能使用var作為類名。
這不是JavaScript。var并不會改變 Java是一門靜態類型語言的事實。編譯器負責推斷出類型,并把結果寫入字節碼文件,就好像是開發人員自己敲入類型一樣。
JDK14中預覽特性:
instanceof 模式匹配通過提供更為簡便的語法,來提高生產力。有了該功能,可以減少Java程序中顯式強制轉換的數量,實現更精確、簡潔的類型安全的代碼。
Java 14之前舊寫法:
if(obj instanceof String){ ? ?String str = (String)obj; //需要強轉 ? .. str.contains(..).. }else{ ? ... }Java 14新特性寫法:
if(obj instanceof String str){ .. str.contains(..).. }else{ ... }舉例:
/** * instanceof的模式匹配(預覽) * * @author shkstart * @create 上午 11:32 */ public class Feature01 { @Test public void test1(){ Object obj = new String("hello,Java14"); obj = null;//在使用null 匹配instanceof 時,返回都是false. if(obj instanceof String){ String str = (String) obj; System.out.println(str.contains("Java")); }else{ System.out.println("非String類型"); } //舉例1: if(obj instanceof String str){ //新特性:省去了強制類型轉換的過程 System.out.println(str.contains("Java")); }else{ System.out.println("非String類型"); } } } // 舉例2 class InstanceOf{ String str = "abc"; public void test(Object obj){ if(obj instanceof String str){//此時的str的作用域僅限于if結構內。 System.out.println(str.toUpperCase()); }else{ System.out.println(str.toLowerCase()); } } } //舉例3: class Monitor{ private String model; private double price; // public boolean equals(Object o){ // if(o instanceof Monitor other){ // if(model.equals(other.model) && price == other.price){ // return true; // } // } // return false; // } public boolean equals(Object o){ return o instanceof Monitor other && model.equals(other.model) && price == other.price; } }JDK15中第二次預覽:
沒有任何更改。
JDK16中轉正特性:
在Java16中轉正。
傳統switch聲明語句的弊端:
匹配是自上而下的,如果忘記寫break,后面的case語句不論匹配與否都會執行; --->case穿透
所有的case語句共用一個塊范圍,在不同的case語句定義的變量名不能重復;
不能在一個case里寫多個執行結果一致的條件;
整個switch不能作為表達式返回值;
JDK12中預覽特性:
Java 12將會對switch聲明語句進行擴展,使用case L ->來替代以前的break;,省去了 break 語句,避免了因少寫 break 而出錯。
同時將多個 case 合并到一行,顯得簡潔、清晰,也更加優雅的表達邏輯分支。
為了保持兼容性,case 條件語句中依然可以使用字符: ,但是同一個 switch 結構里不能混用-> 和: ,否則編譯錯誤。
舉例:
Java 12之前
/** * @author shkstart * @create 下午 4:47 */ public class SwitchTest { public static void main(String[] args) { int numberOfLetters; Fruit fruit = Fruit.APPLE; switch (fruit) { case PEAR: numberOfLetters = 4; break; case APPLE: case GRAPE: case MANGO: numberOfLetters = 5; break; case ORANGE: case PAPAYA: numberOfLetters = 6; break; default: throw new IllegalStateException("No Such Fruit:" + fruit); } System.out.println(numberOfLetters); } } enum Fruit { PEAR, APPLE, GRAPE, MANGO, ORANGE, PAPAYA; }switch 語句如果漏寫了一個 break,那么邏輯往往就跑偏了,這種方式既繁瑣,又容易出錯。
Java 12中:
/** * @author shkstart * @create 下午 10:38 */ public class SwitchTest1 { public static void main(String[] args) { Fruit fruit = Fruit.GRAPE; switch(fruit){ case PEAR -> System.out.println(4); case APPLE,MANGO,GRAPE -> System.out.println(5); case ORANGE,PAPAYA -> System.out.println(6); default -> throw new IllegalStateException("No Such Fruit:" + fruit); }; } }更進一步:
/** * @author shkstart * @create 2019 下午 10:44 */ public class SwitchTest2 { public static void main(String[] args) { Fruit fruit = Fruit.GRAPE; int numberOfLetters = switch(fruit){ case PEAR -> 4; case APPLE,MANGO,GRAPE -> 5; case ORANGE,PAPAYA -> 6; default -> throw new IllegalStateException("No Such Fruit:" + fruit); }; System.out.println(numberOfLetters); } }JDK13中二次預覽特性:
JDK13中引入了yield語句,用于返回值。這意味著,switch表達式(返回值)應該使用yield,switch語句(不返回值)應該使用break。
yield和return的區別在于:return會直接跳出當前循環或者方法,而yield只會跳出當前switch塊。
在以前:
@Test public void testSwitch1(){ String x = "3"; int i; switch (x) { case "1": i=1; break; case "2": i=2; break; default: i = x.length(); break; } System.out.println(i); }在JDK13中:
@Test public void testSwitch2(){ String x = "3"; int i = switch (x) { case "1" -> 1; case "2" -> 2; default -> { yield 3; } }; System.out.println(i); }或者
@Test public void testSwitch3() { String x = "3"; int i = switch (x) { case "1": yield 1; case "2": yield 2; default: yield 3; }; System.out.println(i); }JDK14中轉正特性:
這是JDK 12和JDK 13中的預覽特性,現在是正式特性了。
JDK17的預覽特性:switch的模式匹配
舊寫法:
static String formatter(Object o) { String formatted = "unknown"; if (o instanceof Integer i) { formatted = String.format("int %d", i); } else if (o instanceof Long l) { formatted = String.format("long %d", l); } else if (o instanceof Double d) { formatted = String.format("double %f", d); } else if (o instanceof String s) { formatted = String.format("String %s", s); } return formatted; }模式匹配新寫法:
static String formatterPatternSwitch(Object o) { return switch (o) { case Integer i -> String.format("int %d", i); case Long l -> String.format("long %d", l); case Double d -> String.format("double %f", d); case String s -> String.format("String %s", s); default -> o.toString(); }; }直接在 switch 上支持 Object 類型,這就等于同時支持多種類型,使用模式匹配得到具體類型,大大簡化了語法量,這個功能很實用。
現實問題:
在Java中,通常需要使用String類型表達HTML,XML,SQL或JSON等格式的字符串,在進行字符串賦值時需要進行轉義和連接操作,然后才能編譯該代碼,這種表達方式難以閱讀并且難以維護。
JDK13的新特性
使用"""作為文本塊的開始符和結束符,在其中就可以放置多行的字符串,不需要進行任何轉義。因此,文本塊將提高Java程序的可讀性和可寫性。
基本使用:
""" line1 line2 line3 """相當于:
"line1\nline2\nline3\n"或者一個連接的字符串:
"line1\n" + "line2\n" + "line3\n"如果字符串末尾不需要行終止符,則結束分隔符可以放在最后一行內容上。例如:
""" line1 line2 line3"""相當于
"line1\nline2\nline3"文本塊可以表示空字符串,但不建議這樣做,因為它需要兩行源代碼:
String empty = """ """;舉例1:普通文本
原有寫法:
String text1 = "The Sound of silence\n" + "Hello darkness, my old friend\n" + "I've come to talk with you again\n" + "Because a vision softly creeping\n" + "Left its seeds while I was sleeping\n" + "And the vision that was planted in my brain\n" + "Still remains\n" + "Within the sound of silence"; System.out.println(text1);使用新特性:
String text2 = """ The Sound of silence Hello darkness, my old friend I've come to talk with you again Because a vision softly creeping Left its seeds while I was sleeping And the vision that was planted in my brain Still remains Within the sound of silence """; System.out.println(text2);舉例2:HTML語句
<html> <body> <p>Hello, 尚硅谷</p> </body> </html>將其復制到Java的字符串中,會展示成以下內容:
"<html>\n" + " <body>\n" + " <p>Hello, 尚硅谷</p>\n" + " </body>\n" + "</html>\n";即被自動進行了轉義,這樣的字符串看起來不是很直觀,在JDK 13中:
""" <html> <body> <p>Hello, world</p> </body> </html> """;舉例3:SQL語句
select employee_id,last_name,salary,department_id from employees where department_id in (40,50,60) order by department_id asc原有方式:
String sql = "SELECT id,NAME,email\n" + "FROM customers\n" + "WHERE id > 4\n" + "ORDER BY email DESC";使用新特性:
String sql1 = """ SELECT id,NAME,email FROM customers WHERE id > 4 ORDER BY email DESC """;舉例4:JSON字符串
原有方式:
String myJson = "{\n" + " \"name\":\"Song Hongkang\",\n" + " \"address\":\"www.atguigu.com\",\n" + " \"email\":\"shkstart@126.com\"\n" + "}"; System.out.println(myJson);使用新特性:
String myJson1 = """ { "name":"Song Hongkang", "address":"www.atguigu.com", "email":"shkstart@126.com" }"""; System.out.println(myJson1);JDK14中二次預覽特性
JDK14的版本主要增加了兩個escape sequences,分別是\ <line-terminator>與\s escape sequence。
舉例:
/** * @author shkstart * @create 下午 7:13 */ public class Feature05 { //jdk14新特性 @Test public void test5(){ String sql1 = """ SELECT id,NAME,email FROM customers WHERE id > 4 ORDER BY email DESC """; System.out.println(sql1); // \:取消換行操作 // \s:表示一個空格 String sql2 = """ SELECT id,NAME,email \ FROM customers\s\ WHERE id > 4 \ ORDER BY email DESC """; System.out.println(sql2); } }JDK15中功能轉正
背景
早在2019年2月份,Java 語言架構師 Brian Goetz,曾寫文抱怨“Java太啰嗦”或有太多的“繁文縟節”。他提到:開發人員想要創建純數據載體類(plain data carriers)通常都必須編寫大量低價值、重復的、容易出錯的代碼。如:構造函數、getter/setter、equals()、hashCode()以及toString()等。
以至于很多人選擇使用IDE的功能來自動生成這些代碼。還有一些開發會選擇使用一些第三方類庫,如Lombok等來生成這些方法。
JDK14中預覽特性:神說要用record,于是就有了。實現一個簡單的數據載體類,為了避免編寫:構造函數,訪問器,equals(),hashCode () ,toString ()等,Java 14推出record。
record 是一種全新的類型,它本質上是一個 final 類,同時所有的屬性都是 final 修飾,它會自動編譯出 public get 、hashcode 、equals、toString、構造器等結構,減少了代碼編寫量。
具體來說:當你用record 聲明一個類時,該類將自動擁有以下功能:
獲取成員變量的簡單方法,比如例題中的 name() 和 partner() 。注意區別于我們平常getter()的寫法。
一個 equals 方法的實現,執行比較時會比較該類的所有成員屬性。
重寫 hashCode() 方法。
一個可以打印該類所有成員屬性的 toString() 方法。
只有一個構造方法。
此外:
還可以在record聲明的類中定義靜態字段、靜態方法、構造器或實例方法。
不能在record聲明的類中定義實例字段;類不能聲明為abstract;不能聲明顯式的父類等。
舉例1(舊寫法):
class Point { private final int x; private final int y; Point(int x, int y) { this.x = x; this.y = y; } int x() { return x; } int y() { return y; } public boolean equals(Object o) { if (!(o instanceof Point)) return false; Point other = (Point) o; return other.x == x && other.y == y; } public int hashCode() { return Objects.hash(x, y); } @Override public String toString() { return "Point{" + "x=" + x + ", y=" + y + '}'; } }舉例1(新寫法):
record Point(int x, int y) { }舉例1:
public record Dog(String name, Integer age) { } public class Java14Record { public static void main(String[] args) { Dog dog1 = new Dog("牧羊犬", 1); Dog dog2 = new Dog("田園犬", 2); Dog dog3 = new Dog("哈士奇", 3); System.out.println(dog1); System.out.println(dog2); System.out.println(dog3); } }舉例2:
/** * Record類型的演示 * * @author shkstart * @create 下午 6:13 */ public class Feature07 { @Test public void test1(){ //測試構造器 Person p1 = new Person("羅密歐",new Person("zhuliye",null)); //測試toString() System.out.println(p1); //測試equals(): Person p2 = new Person("羅密歐",new Person("zhuliye",null)); System.out.println(p1.equals(p2)); //測試hashCode()和equals() HashSet<Person> set = new HashSet<>(); set.add(p1); set.add(p2); for (Person person : set) { System.out.println(person); } //測試name()和partner():類似于getName()和getPartner() System.out.println(p1.name()); System.out.println(p1.partner()); } @Test public void test2(){ Person p1 = new Person("zhuyingtai"); System.out.println(p1.getNameInUpperCase()); Person.nation = "CHN"; System.out.println(Person.showNation()); } } /** * @author shkstart * @create 下午 6:20 */ public record Person(String name,Person partner) { //還可以聲明靜態的屬性、靜態的方法、構造器、實例方法 public static String nation; public static String showNation(){ return nation; } public Person(String name){ this(name,null); } public String getNameInUpperCase(){ return name.toUpperCase(); } //不可以聲明非靜態的屬性 // private int id;//報錯 } //不可以將record定義的類聲明為abstract的 //abstract record Order(){ // //} //不可以給record定義的類聲明顯式的父類(非Record類) //record Order() extends Thread{ // //}JDK15中第二次預覽特性
JDK16中轉正特性
最終到JDK16中轉正。
記錄不適合哪些場景
record的設計目標是提供一種將數據建模為數據的好方法。它也不是 JavaBeans 的直接替代品,因為record的方法不符合 JavaBeans 的 get 標準。另外 JavaBeans 通常是可變的,而記錄是不可變的。盡管它們的用途有點像,但記錄并不會以某種方式取代 JavaBean。
背景:
在 Java 中如果想讓一個類不能被繼承和修改,這時我們應該使用 final 關鍵字對類進行修飾。不過這種要么可以繼承,要么不能繼承的機制不夠靈活,有些時候我們可能想讓某個類可以被某些類型繼承,但是又不能隨意繼承,是做不到的。Java 15 嘗試解決這個問題,引入了 sealed 類,被 sealed 修飾的類可以指定子類。這樣這個類就只能被指定的類繼承。
JDK15的預覽特性:
通過密封的類和接口來限制超類的使用,密封的類和接口限制其它可能繼承或實現它們的其它類或接口。
具體使用:
使用修飾符sealed,可以將一個類聲明為密封類。密封的類使用保留關鍵字permits列出可以直接擴展(即extends)它的類。
sealed 修飾的類的機制具有傳遞性,它的子類必須使用指定的關鍵字進行修飾,且只能是 final、sealed、non-sealed 三者之一。
舉例:
package com.atguigu.java; public abstract sealed class Shape permits Circle, Rectangle, Square {...} public final class Circle extends Shape {...} //final表示Circle不能再被繼承了 public sealed class Rectangle extends Shape permits TransparentRectangle, FilledRectangle {...} public final class TransparentRectangle extends Rectangle {...} public final class FilledRectangle extends Rectangle {...} public non-sealed class Square extends Shape {...} //non-sealed表示可以允許任何類繼承JDK16二次預覽特性
JDK17中轉正特性
JDK8的新特性
到目前為止,臭名昭著的空指針異常是導致Java應用程序失敗的最常見原因。以前,為了解決空指針異常,Google在著名的Guava項目引入了Optional類,通過檢查空值的方式避免空指針異常。受到Google的啟發,Optional類已經成為Java 8類庫的一部分。
Optional<T> 類(java.util.Optional) 是一個容器類,它可以保存類型T的值,代表這個值存在?;蛘邇H僅保存null,表示這個值不存在。如果值存在,則isPresent()方法會返回true,調用get()方法會返回該對象。
Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。
創建Optional類對象的方法:
static <T> Optional<T> empty() :用來創建一個空的Optional實例
static <T> Optional<T> of(T value) :用來創建一個Optional實例,value必須非空
static <T> Optional<T> ofNullable(T value) :用來創建一個Optional實例,value可能是空,也可能非空
判斷Optional容器中是否包含對象:
boolean isPresent() : 判斷Optional容器中的值是否存在
void ifPresent(Consumer<? super T> consumer) :判斷Optional容器中的值是否存在,如果存在,就對它進行Consumer指定的操作,如果不存在就不做
獲取Optional容器的對象:
T get(): 如果調用對象包含值,返回該值。否則拋異常。T get()與of(T value)配合使用
T orElse(T other):orElse(T other) 與ofNullable(T value)配合使用,如果Optional容器中非空,就返回所包裝值,如果為空,就用orElse(T other)other指定的默認值(備胎)代替
T orElseGet(Supplier<? extends T> other) :如果Optional容器中非空,就返回所包裝值,如果為空,就用Supplier接口的Lambda表達式提供的值代替
T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果Optional容器中非空,就返回所包裝值,如果為空,就拋出你指定的異常類型代替原來的NoSuchElementException
舉例:
package com.atguigu.optional; import java.util.Optional; import org.junit.Test; public class TestOptional { @Test public void test1(){ String str = "hello"; Optional<String> opt = Optional.of(str); System.out.println(opt); } @Test public void test2(){ Optional<String> opt = Optional.empty(); System.out.println(opt); } @Test public void test3(){ String str = null; Optional<String> opt = Optional.ofNullable(str); System.out.println(opt); } @Test public void test4(){ String str = "hello"; Optional<String> opt = Optional.of(str); String string = opt.get(); System.out.println(string); } @Test public void test5(){ String str = null; Optional<String> opt = Optional.ofNullable(str); // System.out.println(opt.get());//java.util.NoSuchElementException: No value present } @Test public void test6(){ String str = "hello"; Optional<String> opt = Optional.ofNullable(str); String string = opt.orElse("atguigu"); System.out.println(string); } @Test public void test7(){ String str = null; Optional<String> opt = Optional.ofNullable(str); String string = opt.orElseGet(String::new); System.out.println(string); } @Test public void test8(){ String str = null; Optional<String> opt = Optional.ofNullable(str); String string = opt.orElseThrow(()->new RuntimeException("值不存在")); System.out.println(string); } @Test public void test9(){ String str = "Hello1"; Optional<String> opt = Optional.ofNullable(str); //判斷是否是純字母單詞,如果是,轉為大寫,否則保持不變 String result = opt.filter(s->s.matches("[a-zA-Z]+")) .map(s -> s.toUpperCase()).orElse(str); System.out.println(result); } }這是JDK9-11的新特性
boolean isempty() | 判斷value是否為空 | JDK 11 |
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) | value非空,執行參數1功能;如果value為空,執行參數2功能 | JDK 9 |
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) | value非空,返回對應的Optional;value為空,返回形參封裝的Optional | JDK 9 |
Stream<T> stream() | value非空,返回僅包含此value的Stream;否則,返回一個空的Stream | JDK 9 |
T orElseThrow() | value非空,返回value;否則拋異常NoSuchElementException | JDK 10 |
這是JDK9的新特性。
產生背景:
Motivation The current implementation of the String class stores characters in a char array, using two bytes (sixteen bits) for each character. Data gathered from many different applications indicates that strings are a major component of heap usage and, moreover, that most String objects contain only Latin-1 characters. Such characters require only one byte of storage, hence half of the space in the internal char arrays of such String objects is going unused.
使用說明:
We propose to change the internal representation of the String class from a UTF-16 char array to a byte array plus an encoding-flag field. The new String class will store characters encoded either as ISO-8859-1/Latin-1 (one byte per character), or as UTF-16 (two bytes per character), based upon the contents of the string. The encoding flag will indicate which encoding is used.
結論:String 再也不用 char[] 來存儲啦,改成了 byte[] 加上編碼標記,節約了一些空間。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { @Stable private final byte[] value; ... }拓展:StringBuffer 與 StringBuilder
那StringBuffer 和 StringBuilder 是否仍無動于衷呢?
String-related classes such as AbstractStringBuilder, StringBuilder, and StringBuffer will be updated to use the same representation, as will the HotSpot VM's intrinsic string operations.
JDK11新特性:新增了一系列字符串處理方法
判斷字符串是否為空白 | " ".isBlank(); // true |
去除首尾空白 | " Javastack ".strip(); // "Javastack" |
去除尾部空格 | " Javastack ".stripTrailing(); // " Javastack" |
去除首部空格 | " Javastack ".stripLeading(); // "Javastack " |
復制字符串 | "Java".repeat(3);// "JavaJavaJava" |
行數統計 | "A\nB\nC".lines().count(); // 3 |
JDK12新特性:String 實現了 Constable 接口
String源碼:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence,Constable, ConstantDesc {java.lang.constant.Constable接口定義了抽象方法:
public interface Constable { Optional<? extends ConstantDesc> describeConstable(); }Java 12 String 的實現源碼:
/** * Returns an {@link Optional} containing the nominal descriptor for this * instance, which is the instance itself. * * @return an {@link Optional} describing the {@linkplain String} instance * @since 12 */ @Override public Optional<String> describeConstable() { return Optional.of(this); }很簡單,其實就是調用 Optional.of 方法返回一個 Optional 類型。
舉例:
private static void testDescribeConstable() { String name = "尚硅谷Java高級工程師"; Optional<String> optional = name.describeConstable(); System.out.println(optional.get()); }結果輸出:
尚硅谷Java高級工程師JDK12新特性:String新增方法
String的transform(Function)
var result = "foo".transform(input -> input + " bar"); System.out.println(result); //foo bar或者
var result = "foo".transform(input -> input + " bar").transform(String::toUpperCase) System.out.println(result); //FOO BAR對應的源碼:
/** * This method allows the application of a function to {@code this} * string. The function should expect a single String argument * and produce an {@code R} result. * @since 12 */ public <R> R transform(Function<? super String, ? extends R> f) { return f.apply(this); }在某種情況下,該方法應該被稱為map()。
舉例:
private static void testTransform() { System.out.println("======test java 12 transform======"); List<String> list1 = List.of("Java", " Python", " C++ "); List<String> list2 = new ArrayList<>(); list1.forEach(element -> list2.add(element.transform(String::strip) .transform(String::toUpperCase) .transform((e) -> "Hi," + e)) ); list2.forEach(System.out::println); }結果輸出:
======test java 12 transform====== Hi,JAVA Hi,PYTHON Hi,C++如果使用Java 8的Stream特性,可以如下實現:
private static void testTransform1() { System.out.println("======test before java 12 ======"); List<String> list1 = List.of("Java ", " Python", " C++ "); Stream<String> stringStream = list1.stream().map(element -> element.strip()).map(String::toUpperCase).map(element -> "Hello," + element); List<String> list2 = stringStream.collect(Collectors.toList()); list2.forEach(System.out::println); }Applet API 提供了一種將 Java AWT/Swing 控件嵌入到瀏覽器網頁中的方法。不過,目前 Applet 已經被淘汰。大部分人可能壓根就沒有用過 Applet。
Applet API 實際上是無用的,因為所有 Web 瀏覽器供應商都已刪除或透露計劃放棄對 Java 瀏覽器插件的支持。Java 9 的時候,Applet API 已經被標記為過時,Java 17 的時候終于標記為刪除了。
具體如下:
java.applet.Applet java.applet.AppletStub java.applet.AppletContext java.applet.AudioClip javax.swing.JApplet java.beans.AppletInitializer在java 8 中,標識符可以獨立使用“_”來命名:
String _ = "hello"; System.out.println(_);但是,在java 9 中規定“_”不再可以單獨命名標識符了,如果使用,會報錯:
??
看下面的代碼。
// 編譯 javac JavaStack.java // 運行 java JavaStack我們的認知里,要運行一個 Java 源代碼必須先編譯,再運行。而在 Java 11 版本中,通過一個 java 命令就直接搞定了,如下所示:
java JavaStack.java注意點:
執行源文件中的第一個類,第一個類必須包含主方法。
GC是Java主要優勢之一。 然而,當GC停頓太長,就會開始影響應用的響應時間。隨著現代系統中內存不斷增長,用戶和程序員希望JVM能夠以高效的方式充分利用這些內存, 并且無需長時間的GC暫停時間。
8.3.1 G1 GC
JDK9以后默認的垃圾回收器是G1GC。
JDK10 : 為G1提供并行的Full GC
G1最大的亮點就是可以盡量的避免full gc。但畢竟是“盡量”,在有些情況下,G1就要進行full gc了,比如如果它無法足夠快的回收內存的時候,它就會強制停止所有的應用線程然后清理。
在Java10之前,一個單線程版的標記-清除-壓縮算法被用于full gc。為了盡量減少full gc帶來的影響,在Java10中,就把之前的那個單線程版的標記-清除-壓縮的full gc算法改成了支持多個線程同時full gc。這樣也算是減少了full gc所帶來的停頓,從而提高性能。
你可以通過-XX:ParallelGCThreads參數來指定用于并行GC的線程數。
JDK12:可中斷的 G1 Mixed GC
JDK12:增強G1,自動返回未用堆內存給操作系統
8.3.2 Shenandoah GC
JDK12:Shenandoah GC:低停頓時間的GC
??
Shenandoah 垃圾回收器是 Red Hat 在 2014 年宣布進行的一項垃圾收集器研究項目 Pauseless GC 的實現,旨在針對 JVM 上的內存收回實現低停頓的需求。
據 Red Hat 研發 Shenandoah 團隊對外宣稱,Shenandoah 垃圾回收器的暫停時間與堆大小無關,這意味著無論將堆設置為 200 MB 還是 200 GB,都將擁有一致的系統暫停時間,不過實際使用性能將取決于實際工作堆的大小和工作負載。
Shenandoah GC 主要目標是 99.9% 的暫停小于 10ms,暫停與堆大小無關等。
這是一個實驗性功能,不包含在默認(Oracle)的OpenJDK版本中。
Shenandoah開發團隊在實際應用中的測試數據:
?
JDK15:Shenandoah垃圾回收算法轉正
Shenandoah垃圾回收算法終于從實驗特性轉變為產品特性,這是一個從 JDK 12 引入的回收算法,該算法通過與正在運行的 Java 線程同時進行疏散工作來減少 GC 暫停時間。Shenandoah 的暫停時間與堆大小無關,無論堆棧是 200 MB 還是 200 GB,都具有相同的一致暫停時間。
Shenandoah在JDK12被作為experimental引入,在JDK15變為Production;之前需要通過-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC來啟用,現在只需要-XX:+UseShenandoahGC即可啟用
8.3.3 革命性的 ZGC
JDK11:引入革命性的 ZGC
ZGC,這應該是JDK11最為矚目的特性,沒有之一。
ZGC是一個并發、基于region、壓縮型的垃圾收集器。
ZGC的設計目標是:支持TB級內存容量,暫停時間低(<10ms),對整個程序吞吐量的影響小于15%。 將來還可以擴展實現機制,以支持不少令人興奮的功能,例如多層堆(即熱對象置于DRAM和冷對象置于NVMe閃存),或壓縮堆。
JDK13:ZGC:將未使用的堆內存歸還給操作系統
JDK14:ZGC on macOS和windows
JDK14之前,ZGC僅Linux才支持?,F在mac或Windows上也能使用ZGC了,示例如下:
-XX:+UnlockExperimentalVMOptions -XX:+UseZGCZGC與Shenandoah目標高度相似,在盡可能對吞吐量影響不大的前提下,實現在任意堆內存大小下都可以把垃圾收集的停頓時間限制在十毫秒以內的低延遲。
?
?
?
JDK15:ZGC 功能轉正
ZGC是Java 11引入的新的垃圾收集器,經過了多個實驗階段,自此終于成為正式特性。
但是這并不是替換默認的GC,默認的GC仍然還是G1;之前需要通過-XX:+UnlockExperimentalVMOptions、-XX:+UseZGC來啟用ZGC,現在只需要-XX:+UseZGC就可以。相信不久的將來它必將成為默認的垃圾回收器。
ZGC的性能已經相當亮眼,用“令人震驚、革命性”來形容,不為過。未來將成為服務端、大內存、低延遲應用的首選垃圾收集器。
怎么形容Shenandoah和ZGC的關系呢?異同點大概如下:
相同點:性能幾乎可認為是相同的
不同點:ZGC是Oracle JDK的,根正苗紅。而Shenandoah只存在于OpenJDK中,因此使用時需注意你的JDK版本
JDK16:ZGC 并發線程處理
在線程的堆棧處理過程中,總有一個制約因素就是safepoints。在safepoints這個點,Java的線程是要暫停執行的,從而限制了GC的效率。
回顧:
我們都知道,在之前,需要 GC 的時候,為了進行垃圾回收,需要所有的線程都暫停下來,這個暫停的時間我們稱為 Stop The World。
而為了實現 STW 這個操作, JVM 需要為每個線程選擇一個點停止運行,這個點就叫做安全點(Safepoints)。
而ZGC的并發線程堆棧處理可以保證Java線程可以在GC safepoints的同時可以并發執行。它有助于提高所開發的Java軟件應用程序的性能和效率。
隨著云計算和 AI 等技術浪潮,當前的計算模式和場景正在發生翻天覆地的變化,不僅對 Java 的發展速度提出了更高要求,也深刻影響著 Java 技術的發展方向。傳統的大型企業或互聯網應用,正在被云端、容器化應用、模塊化的微服務甚至是函數(FaaS, Function-as-a-Service)所替代。
Java 需要在新的計算場景下,改進開發效率。比如,Java 代碼雖然進行了一些類型推斷等改進,更易用的集合 API 等,但仍然給開發者留下了過于刻板、形式主義的印象,這是一個長期的改進方向。
Java雖然標榜面向對象編程,卻毫不顧忌的加入面向接口編程思想,又扯出匿名對象的概念,每增加一個新的東西,對Java的根本(面向對象思想)的一次沖擊。
士,不可不弘毅,任重而道遠。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
常德市十一中和育才哪個好?十一中好!市十一中興辦于2000年7月,地處城區中心,東臨朗州路,北接濱湖路,南望洞庭大道,位置優越,交通便利,環境幽雅,是省級“園林式”單位,省級“文明衛生”單位,市級“綠色學?!?。幾年來,學校堅持“育人是根本,校風是靈魂,教師是關鍵,教學為中心,科研為先導,質量為生命”的辦學思想,求真務實,勵精圖治。常德市育才中學是2019年8月經常德市人民政府批準成立的一所獨立公辦...
testflight 3.0怎么用?Testflight是一款面向開發人員的測試應用軟件。作為開發人員,您可以通過電子郵件邀請測試。如果你不知道如何使用它,你可以看看下面的教程。打開iPhone上的app store軟件進行搜索,或直接從當前軟件園下載最新版本的testflight;1。如果提示您是否允許[推送通知],則我們選擇允許;2?,F在,軟件中沒有內容,您需要等待開發人員邀請測試,然后才能正...
什么叫RSS源?RSS為Really Simple Syndication(簡易工具供稿)的縮寫,是某一站點用處和其它站點之間鏈接共享內容的一種簡易,也叫聚合體內容。RSS,原意是把網站內容如標題、鏈接、部分內文甚至還加番裝換為可向外延伸標示語言(XML:eXtensible MarkupLanguage)的格式Reeder 4,你認為它依然是最好的RSS閱讀器嗎?“頭條”本身,當然是三個浩大的R...