讲师:尚硅谷-宋红康(江湖人称:康师傅)
官网:http://www.atguigu.com
新的语法结构,为我们勾勒出了 Java 语法进化的一个趋势SEO靠我,将开发者从复杂、繁琐的低层次抽象中逐渐解放出来,以更高层次、更优雅的抽象,既降低代码量,又避免意外编程错误的出现,进而提高代码质量和开发效率。
JDKSEO靠我9的新特性
Java 终于拥有了像Python 和 Scala 之类语言的REPL工具(交互式编程环境,read - evaluate - print - loop):jShell。以交互式的方式对语句SEO靠我和表达式进行求值。即写即得、快速运行。
利用jShell在没有创建类的情况下,在命令行里直接声明变量,计算表达式,执行语句。无需跟人解释”public static void main(String[]SEO靠我 args)”这句"废话"。
使用举例
调出jShell
获取帮助
基本使用
导入指定的包
默认已经导入如下的所有包:(包含java.lang包)
只需按下 Tab 键,就能自动补全代码
列出当前 session 里SEO靠我所有有效的代码片段
查看当前 session 下所有创建过的变量
查看当前 session 下所有创建过的方法
Tips:我们还可以重新定义相同方法名和参数列表的方法,即对现有方法的修改(或覆盖)。
使用外部SEO靠我代码编辑器来编写 Java 代码
从外部文件加载源代码【HelloWorld.java】
/** * Created by songhongkang */ SEO靠我public void printHello() { System.out.println("马上2023年了,尚硅谷祝所有的谷粉元旦快乐!"); } SEO靠我 printHello(); 使用/open命令调用
退出jShell
在JDK7 之前,我们这样处理资源的关闭:
@Test SEO靠我 public void test01() { FileWriter fw = null; BufferedWriter bw = null; SEO靠我 try { fw = new FileWriter("d:/1.txt"); bw = new BufferedWriter(fSEO靠我w); bw.write("hello"); } catch (IOException e) { eSEO靠我.printStackTrace(); } finally { try { if (bw != null) { SEO靠我 bw.close(); } } catch (IOException e) { SEO靠我 e.printStackTrace(); } try { if (fw !=SEO靠我 null) { fw.close(); } } catch (IOException eSEO靠我) { e.printStackTrace(); } } }JDK7的新特性
在SEO靠我try的后面可以增加一个(),在括号中可以声明流对象并初始化。try中的代码执行完毕,会自动把流对象释放,就不用写finally了。
格式:
try(资源对象的声明和初始化){ 业务SEO靠我逻辑代码,可能会产生异常 }catch(异常类型1 e){ 处理异常代码 }catch(异常类型2 e){ 处理异常代码 SEO靠我 }说明:
1、在try()中声明的资源,无论是否发生异常,无论是否处理异常,都会自动关闭资源对象,不用手动关闭了。
2、这些资源实现类必须实现AutoCloseable或Closeable接SEO靠我口,实现其中的close()方法。Closeable是AutoCloseable的子接口。Java7几乎把所有的“资源类”(包括文件IO的各种类、JDBC编程的Connection、StatementSEO靠我等接口…)都进行了改写,改写后资源类都实现了AutoCloseable或Closeable接口,并实现了close()方法。
3、写到try()中的资源类的变量默认是final声明的,不能修改。
举例:
/SEO靠我/举例1 @Test public void test02() { try ( FileWriter fw = neSEO靠我w FileWriter("d:/1.txt"); BufferedWriter bw = new BufferedWriter(fw); ) { SEO靠我 bw.write("hello"); } catch (IOException e) { e.printStackTracSEO靠我e(); } } //举例2 @Test public void test03() { SEO靠我 //从d:/1.txt(utf-8)文件中,读取内容,写到项目根目录下1.txt(gbk)文件中 try ( FileInputStrSEO靠我eam fis = new FileInputStream("d:/1.txt"); InputStreamReader isr = new InputStreamReaSEO靠我der(fis, "utf-8"); BufferedReader br = new BufferedReader(isr); SEO靠我 FileOutputStream fos = new FileOutputStream("1.txt"); OutputStreamWriter osw = neSEO靠我w OutputStreamWriter(fos, "gbk"); BufferedWriter bw = new BufferedWriter(osw); SEO靠我 ) { String str; while ((str = br.readLine()) != null) { SEO靠我 bw.write(str); bw.newLine(); } } catch (FileNotFSEO靠我oundException e) { e.printStackTrace(); } catch (IOException e) { SEO靠我 e.printStackTrace(); } }JDK9的新特性
try的前面可以定义流对象,try后面的()中可以直接引用流对象的名称。在try代码执行SEO靠我完毕后,流对象也可以释放掉,也不用写finally了。
格式:
A a = new A(); B b = new B(); try(a;b){ 可能产SEO靠我生的异常代码 }catch(异常类名 变量名){ 异常处理的逻辑 }举例:
@Test public void test04() {SEO靠我 InputStreamReader reader = new InputStreamReader(System.in); OutputStreamWritSEO靠我er writer = new OutputStreamWriter(System.out); try (reader; writer) { //rSEO靠我eader是final的,不可再被赋值 // reader = null; } catch (IOException e) {SEO靠我 e.printStackTrace(); } }JDK 10的新特性
局部变量的显示类型声明,常常被认为是不必SEO靠我须的,给一个好听的名字反而可以很清楚的表达出下面应该怎样继续。本新特性允许开发人员省略通常不必要的局部变量类型声明,以增强Java语言的体验性、可读性。
使用举例
//1.局部变量的实例化 SEO靠我 var list = new ArrayList<String>(); var set = new LinkedHashSet<Integer>(); SEO靠我 //2.增强for循环中的索引 for (var v : list) { System.out.println(v); SEO靠我} //3.传统for循环中 for (var i = 0; i < 100; i++) { System.out.printSEO靠我ln(i); } //4. 返回值类型含复杂泛型结构 var iterator = set.iterator(); SEO靠我//Iterator<Map.Entry<Integer, Student>> iterator = set.iterator(); 不适用场景
声明一个成员变量
声明一个数组变量,并为SEO靠我数组静态初始化(省略new的情况下)
方法的返回值类型
方法的参数类型
没有初始化的方法内的局部变量声明
作为catch块中异常类型
Lambda表达式中函数式接口的类型
方法引用中函数式接口的类型
代码举例:
声明SEO靠我一个成员变量,并初始化值为null
声明一个数组变量,并为数组静态初始化(省略new的情况下)
没有初始化的方法内的局部变量声明
方法的返回值类型
方法的参数类型
构造器的参数类型
作为catch块中异常类型
LaSEO靠我mbda表达式中函数式接口的类型
方法引用中函数式接口的类型
注意:
var不是一个关键字,而是一个类型名,将它作为变量的类型。不能使用var作为类名。
这不是JavaScript。var并不会改变 JavaSEO靠我是一门静态类型语言的事实。编译器负责推断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样。
JDK14中预览特性:
instanceof 模式匹配通过SEO靠我提供更为简便的语法,来提高生产力。有了该功能,可以减少Java程序中显式强制转换的数量,实现更精确、简洁的类型安全的代码。
Java 14之前旧写法:
if(obj instanceof String){SEO靠我 String str = (String)obj; //需要强转 .. str.contains(..).. }else{ SEO靠我 ... }Java 14新特性写法:
if(obj instanceof String str){ .. str.contains(..).. }elSEO靠我se{ ... }举例:
/** * instanceof的模式匹配(预览) * * @author shkstart SEO靠我 * @create 上午 11:32 */ public class Feature01 { @Test public vSEO靠我oid test1(){ Object obj = new String("hello,Java14"); obj = null;//在使用null 匹配instanSEO靠我ceof 时,返回都是false. if(obj instanceof String){ String str = (String) obj; SystSEO靠我em.out.println(str.contains("Java")); }else{ System.out.println("非String类型"); SEO靠我 } //举例1: if(obj instanceof String str){ //新特性:省去了强制类型转换的过程 System.out.priSEO靠我ntln(str.contains("Java")); }else{ System.out.println("非String类型"); } SEO靠我 } } // 举例2 class InstanceOf{ String str = "abc"; publicSEO靠我 void test(Object obj){ if(obj instanceof String str){//此时的str的作用域仅限于if结构内。 System.SEO靠我out.println(str.toUpperCase()); }else{ System.out.println(str.toLowerCase()); SEO靠我 } } } //举例3: class Monitor{ private String model; SEO靠我 private double price; // public boolean equals(Object o){ // if(o instanceof MonSEO靠我itor other){ // if(model.equals(other.model) && price == other.price){ // return truSEO靠我e; // } // } // return false; // } public boolean equals(OSEO靠我bject o){ return o instanceof Monitor other && model.equals(other.model) && price == other.pSEO靠我rice; } }JDK15中第二次预览:
没有任何更改。
JDK16中转正特性:
在Java16中转正。
传统switch声明语句的弊端:
匹配是自SEO靠我上而下的,如果忘记写break,后面的case语句不论匹配与否都会执行; --->case穿透
所有的case语句共用一个块范围,在不同的case语句定义的变量名不能重复;
不能在一个case里写多个执行SEO靠我结果一致的条件;
整个switch不能作为表达式返回值;
//常见错误实现 switch(month){ case 3|4|5://3|4|5 用了位运算符,11 | 10SEO靠我0 | 101结果是 111是7 System.out.println("春季"); break; case 6|7|8://6|7|8用了位运算符,1SEO靠我10 | 111 | 1000结果是1111是15 System.out.println("夏季"); break; case 9|10|11://9|SEO靠我10|11用了位运算符,1001 | 1010 | 1011结果是1011是11 System.out.println("秋季"); break; caSEO靠我se 12|1|2://12|1|2 用了位运算符,1100 | 1 | 10 结果是1111,是15 System.out.println("冬季"); break;SEO靠我 default: System.out.println("输入有误"); }JDK12中预览特性:
Java 12将会对switch声明语句进行扩展,使SEO靠我用case L ->来替代以前的break;,省去了 break 语句,避免了因少写 break 而出错。
同时将多个 case 合并到一行,显得简洁、清晰,也更加优雅的表达逻辑分支。
为了保持兼容性,cSEO靠我ase 条件语句中依然可以使用字符: ,但是同一个 switch 结构里不能混用-> 和: ,否则编译错误。
举例:
Java 12之前
/** * @author shkstart SEO靠我 * @create 下午 4:47 */ public class SwitchTest { public static void main(SEO靠我String[] args) { int numberOfLetters; Fruit fruit = Fruit.APPLE; switch (fruSEO靠我it) { case PEAR: numberOfLetters = 4; break; case APPLE: casSEO靠我e GRAPE: case MANGO: numberOfLetters = 5; break; case ORANGE: SEO靠我 case PAPAYA: numberOfLetters = 6; break; default: throw new IllegaSEO靠我lStateException("No Such Fruit:" + fruit); } System.out.println(numberOfLetters); SEO靠我 } } enum Fruit { PEAR, APPLE, GRAPE, MANGO, ORANGE, PAPAYA; }SEO靠我switch 语句如果漏写了一个 break,那么逻辑往往就跑偏了,这种方式既繁琐,又容易出错。
Java 12中:
/** * @author shkstart * @cSEO靠我reate 下午 10:38 */ public class SwitchTest1 { public static void main(String[SEO靠我] args) { Fruit fruit = Fruit.GRAPE; switch(fruit){ case PEAR -> System.out.SEO靠我println(4); case APPLE,MANGO,GRAPE -> System.out.println(5); case ORANGE,PAPAYA -> SSEO靠我ystem.out.println(6); default -> throw new IllegalStateException("No Such Fruit:" + fruit); SEO靠我 }; } }更进一步:
/** * @author shkstart * @create 2019 下午 10:44 SEO靠我 */ public class SwitchTest2 { public static void main(String[] args) { SEO靠我 Fruit fruit = Fruit.GRAPE; int numberOfLetters = switch(fruit){ case PEAR -> 4; SEO靠我 case APPLE,MANGO,GRAPE -> 5; case ORANGE,PAPAYA -> 6; default -> throw new IlleSEO靠我galStateException("No Such Fruit:" + fruit); }; System.out.println(numberOfLetters);SEO靠我 } }JDK13中二次预览特性:
JDK13中引入了yield语句,用于返回值。这意味着,switch表达式(返回值)应该使用yield,switch语句(不返回值)应SEO靠我该使用break。
yield和return的区别在于:return会直接跳出当前循环或者方法,而yield只会跳出当前switch块。
在以前:
@Test public void tesSEO靠我tSwitch1(){ String x = "3"; int i; switch (x) { case "1": i=SEO靠我1; break; case "2": i=2; break; default: i = x.lengtSEO靠我h(); break; } System.out.println(i); }在JDK13中:
@Test public vSEO靠我oid testSwitch2(){ String x = "3"; int i = switch (x) { case "1" -> 1; SEO靠我 case "2" -> 2; default -> { yield 3; } }; System.out.prinSEO靠我tln(i); }或者
@Test public void testSwitch3() { String x = "3"; int i =SEO靠我 switch (x) { case "1": yield 1; case "2": yield 2; default:SEO靠我 yield 3; }; System.out.println(i); }JDK14中转正特性:
这是JDK 12和JDK 13中的预览特SEO靠我性,现在是正式特性了。
JDK17的预览特性:switch的模式匹配
旧写法:
static String formatter(Object o) { String formatted = SEO靠我"unknown"; if (o instanceof Integer i) { formatted = String.format("int %d", i); SEO靠我 } else if (o instanceof Long l) { formatted = String.format("long %d", l); } elSEO靠我se if (o instanceof Double d) { formatted = String.format("double %f", d); } else ifSEO靠我 (o instanceof String s) { formatted = String.format("String %s", s); } retuSEO靠我rn formatted; }模式匹配新写法:
static String formatterPatternSwitch(Object o) { return switcSEO靠我h (o) { case Integer i -> String.format("int %d", i); case Long l -> String.format("SEO靠我long %d", l); case Double d -> String.format("double %f", d); case String s -> StrinSEO靠我g.format("String %s", s); default -> o.toString(); }; }直接在 switch 上支持 ObjectSEO靠我 类型,这就等于同时支持多种类型,使用模式匹配得到具体类型,大大简化了语法量,这个功能很实用。
现实问题:
在Java中,通常需要使用String类型表达HTML,XML,SQL或JSON等SEO靠我格式的字符串,在进行字符串赋值时需要进行转义和连接操作,然后才能编译该代码,这种表达方式难以阅读并且难以维护。
JDK13的新特性
使用"""作为文本块的开始符和结束符,在其中就可以放置多行的字符串,不需SEO靠我要进行任何转义。因此,文本块将提高Java程序的可读性和可写性。
基本使用:
""" line1 line2 line3 """相当于:
"lSEO靠我ine1\nline2\nline3\n"或者一个连接的字符串:
"line1\n" + "line2\n" + "line3\n"如果字符串末尾不需要行终止符,则结束分SEO靠我隔符可以放在最后一行内容上。例如:
""" line1 line2 line3"""相当于
"line1\nline2\nline3"文本块可以表示空字符串SEO靠我,但不建议这样做,因为它需要两行源代码:
String empty = """ """;举例1:普通文本
原有写法:
String text1 = "The Sound of silenceSEO靠我\n" + "Hello darkness, my old friend\n" + "Ive come to talk with you again\n" + SEO靠我 "Because a vision softly creeping\n" + "Left its seeds while I was sleeping\n" + SEO靠我 "And the vision that was planted in my brain\n" + "Still remains\n" + "Within the sSEO靠我ound of silence"; System.out.println(text1);使用新特性:
String text2 = """ The Sound of sSEO靠我ilence Hello darkness, my old friend Ive come to talk with you again BecauseSEO靠我 a vision softly creeping Left its seeds while I was sleeping And the vision that waSEO靠我s planted in my brain Still remains Within the sound of silence """; SEO靠我 System.out.println(text2);举例2:HTML语句
<html> <body> <p>Hello, 尚硅谷</p> </body>SEO靠我 </html>将其复制到Java的字符串中,会展示成以下内容:
"<html>\n" + " <body>\n" + " <p>Hello, 尚硅谷</SEO靠我p>\n" + " </body>\n" + "</html>\n";即被自动进行了转义,这样的字符串看起来不是很直观,在JDK 13中:
""" <htSEO靠我ml> <body> <p>Hello, world</p> </body> </html> """;举例3:SQL语句SEO靠我
select employee_id,last_name,salary,department_id from employees where department_idSEO靠我 in (40,50,60) order by department_id asc原有方式:
String sql = "SELECT id,NAME,email\n" + SEO靠我 "FROM customers\n" + "WHERE id > 4\n" + "ORDER BY email DESC";使用新特性:
String sql1 = SEO靠我""" SELECT id,NAME,email FROM customers WHERE id > 4 ORDER BY email SEO靠我DESC """;举例4:JSON字符串
原有方式:
String myJson = "{\n" + " \"name\":\"Song Hongkang\",\n" + SEO靠我 " \"address\":\"www.atguigu.com\",\n" + " \"email\":\"shkstart@126.com\"\n" + SEO靠我 "}"; System.out.println(myJson);使用新特性:
String myJson1 = """ { "name":"Song SEO靠我Hongkang", "address":"www.atguigu.com", "email":"shkstart@126.com" }"""; SEO靠我 System.out.println(myJson1);JDK14中二次预览特性
JDK14的版本主要增加了两个escape sequences,分别是\ <line-terminator>与SEO靠我\s escape sequence。
举例:
/** * @author shkstart * @create 下午 7:13 */ puSEO靠我blic class Feature05 { //jdk14新特性 @Test public void test5(){ String SEO靠我sql1 = """ SELECT id,NAME,email FROM customers WHERE id > 4 ORDER BYSEO靠我 email DESC """; System.out.println(sql1); // \:取消换行操作 // \s:表示一个空格SEO靠我 String sql2 = """ SELECT id,NAME,email \ FROM customers\s\ WHERE idSEO靠我 > 4 \ ORDER BY email DESC """; System.out.println(sql2); } SEO靠我}JDK15中功能转正
背景
早在2019年2月份,Java 语言架构师 Brian Goetz,曾写文抱怨“Java太啰嗦”或有太多的“繁文缛节”。他提到:开发人员想要创建纯数据载体SEO靠我类(plain data carriers)通常都必须编写大量低价值、重复的、容易出错的代码。如:构造函数、getter/setter、equals()、hashCode()以及toString()等SEO靠我。
以至于很多人选择使用IDE的功能来自动生成这些代码。还有一些开发会选择使用一些第三方类库,如Lombok等来生成这些方法。
JDK14中预览特性:神说要用record,于是就有了。实现一个简单的数据载SEO靠我体类,为了避免编写:构造函数,访问器,equals(),hashCode () ,toString ()等,Java 14推出record。
record 是一种全新的类型,它本质上是一个 final SEO靠我类,同时所有的属性都是 final 修饰,它会自动编译出 public get 、hashcode 、equals、toString、构造器等结构,减少了代码编写量。
具体来说:当你用record 声明SEO靠我一个类时,该类将自动拥有以下功能:
获取成员变量的简单方法,比如例题中的 name() 和 partner() 。注意区别于我们平常getter()的写法。
一个 equals 方法的实现,执行比较时会比SEO靠我较该类的所有成员属性。
重写 hashCode() 方法。
一个可以打印该类所有成员属性的 toString() 方法。
只有一个构造方法。
此外:
还可以在record声明的类中定义静态字段、静态方法、构造器SEO靠我或实例方法。
不能在record声明的类中定义实例字段;类不能声明为abstract;不能声明显式的父类等。
举例1(旧写法):
class Point { private final inSEO靠我t x; private final int y; Point(int x, int y) { this.x = x; this.y SEO靠我= y; } int x() { return x; } int y() { return y; SEO靠我 } public boolean equals(Object o) { if (!(o instanceof Point)) return false;SEO靠我 Point other = (Point) o; return other.x == x && other.y == y; } puSEO靠我blic int hashCode() { return Objects.hash(x, y); } @Override publicSEO靠我 String toString() { return "Point{" + "x=" + x + ", y=" + y + }; SEO靠我 } }举例1(新写法):
record Point(int x, int y) { }举例1:
public record Dog(String name, Integer aSEO靠我ge) { } public class Java14Record { public static void main(String[] args) SEO靠我{ Dog dog1 = new Dog("牧羊犬", 1); Dog dog2 = new Dog("田园犬", 2); Dog dog3 = newSEO靠我 Dog("哈士奇", 3); System.out.println(dog1); System.out.println(dog2); System.oSEO靠我ut.println(dog3); } }举例2:
/** * Record类型的演示 * * @author shkstSEO靠我art * @create 下午 6:13 */ public class Feature07 { @Test publSEO靠我ic void test1(){ //测试构造器 Person p1 = new Person("罗密欧",new Person("zhuliye",null)); SEO靠我 //测试toString() System.out.println(p1); //测试equals(): Person p2 = new SEO靠我Person("罗密欧",new Person("zhuliye",null)); System.out.println(p1.equals(p2)); //测试haSEO靠我shCode()和equals() HashSet<Person> set = new HashSet<>(); set.add(p1); set.adSEO靠我d(p2); for (Person person : set) { System.out.println(person); } /SEO靠我/测试name()和partner():类似于getName()和getPartner() System.out.println(p1.name()); System.SEO靠我out.println(p1.partner()); } @Test public void test2(){ Person p1 SEO靠我= new Person("zhuyingtai"); System.out.println(p1.getNameInUpperCase()); Person.naSEO靠我tion = "CHN"; System.out.println(Person.showNation()); } } /** SEO靠我 * @author shkstart * @create 下午 6:20 */ public record Person(String nameSEO靠我,Person partner) { //还可以声明静态的属性、静态的方法、构造器、实例方法 public static String nation; SEO靠我 public static String showNation(){ return nation; } public Person(StringSEO靠我 name){ this(name,null); } public String getNameInUpperCase(){ retuSEO靠我rn name.toUpperCase(); } //不可以声明非静态的属性 // private int id;//报错 } SEO靠我 //不可以将record定义的类声明为abstract的 //abstract record Order(){ // //} SEO靠我 //不可以给record定义的类声明显式的父类(非Record类) //record Order() extends Thread{ // //}JDSEO靠我K15中第二次预览特性
JDK16中转正特性
最终到JDK16中转正。
记录不适合哪些场景
record的设计目标是提供一种将数据建模为数据的好方法。它也不是 JavaBeans 的直接替代品,因为recorSEO靠我d的方法不符合 JavaBeans 的 get 标准。另外 JavaBeans 通常是可变的,而记录是不可变的。尽管它们的用途有点像,但记录并不会以某种方式取代 JavaBean。
背景:SEO靠我
在 Java 中如果想让一个类不能被继承和修改,这时我们应该使用 final 关键字对类进行修饰。不过这种要么可以继承,要么不能继承的机制不够灵活,有些时候我们可能想让某个类可以被某些类型继承,但是又SEO靠我不能随意继承,是做不到的。Java 15 尝试解决这个问题,引入了 sealed 类,被 sealed 修饰的类可以指定子类。这样这个类就只能被指定的类继承。
JDK15的预览特性:
通过密封的类和接口来SEO靠我限制超类的使用,密封的类和接口限制其它可能继承或实现它们的其它类或接口。
具体使用:
使用修饰符sealed,可以将一个类声明为密封类。密封的类使用保留关键字permits列出可以直接扩展(即extendSEO靠我s)它的类。
sealed 修饰的类的机制具有传递性,它的子类必须使用指定的关键字进行修饰,且只能是 final、sealed、non-sealed 三者之一。
举例:
package com.atguigSEO靠我u.java; public abstract sealed class Shape permits Circle, Rectangle, Square {...} SEO靠我public final class Circle extends Shape {...} //final表示Circle不能再被继承了 public sealed class ReSEO靠我ctangle extends Shape permits TransparentRectangle, FilledRectangle {...} public final clasSEO靠我s TransparentRectangle extends Rectangle {...} public final class FilledRectangle extends RSEO靠我ectangle {...} public non-sealed class Square extends Shape {...} //non-sealed表示可以允许任何类继承JDSEO靠我K16二次预览特性
JDK17中转正特性
JDK8的新特性
到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,GoSEO靠我ogle在著名的Guava项目引入了Optional类,通过检查空值的方式避免空指针异常。受到Google的启发,Optional类已经成为Java 8类库的一部分。
Optional<T> 类(javSEO靠我a.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。如果值存在,则isPresent()方法会返回true,调用get()方法SEO靠我会返回该对象。
Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
创建Optional类对象的方法:
static <T> Optional<T> empty() :用来创建一个空的OpSEO靠我tional实例
static <T> Optional<T> of(T value) :用来创建一个Optional实例,value必须非空
static <T> Optional<T> ofNullaSEO靠我ble(T value) :用来创建一个Optional实例,value可能是空,也可能非空
判断Optional容器中是否包含对象:
boolean isPresent() : 判断Optional容器SEO靠我中的值是否存在
void ifPresent(Consumer<? super T> consumer) :判断Optional容器中的值是否存在,如果存在,就对它进行Consumer指定的操作,如果不SEO靠我存在就不做
获取Optional容器的对象:
T get(): 如果调用对象包含值,返回该值。否则抛异常。T get()与of(T value)配合使用
T orElse(T other):orElse(TSEO靠我 other) 与ofNullable(T value)配合使用,如果Optional容器中非空,就返回所包装值,如果为空,就用orElse(T other)other指定的默认值(备胎)代替
T orSEO靠我ElseGet(Supplier<? extends T> other) :如果Optional容器中非空,就返回所包装值,如果为空,就用Supplier接口的Lambda表达式提供的值代替
T orESEO靠我lseThrow(Supplier<? extends X> exceptionSupplier) :如果Optional容器中非空,就返回所包装值,如果为空,就抛出你指定的异常类型代替原来的NoSuSEO靠我chElementException
举例:
package com.atguigu.optional; import java.util.Optional; impoSEO靠我rt org.junit.Test; public class TestOptional { @Test public void test1(){ SEO靠我 String str = "hello"; Optional<String> opt = Optional.of(str); System.out.priSEO靠我ntln(opt); } @Test public void test2(){ Optional<String> opt = OptioSEO靠我nal.empty(); System.out.println(opt); } @Test public void test3(){ SEO靠我 String str = null; Optional<String> opt = Optional.ofNullable(str); System.ouSEO靠我t.println(opt); } @Test public void test4(){ String str = "hello"; SEO靠我 Optional<String> opt = Optional.of(str); String string = opt.get(); System.oSEO靠我ut.println(string); } @Test public void test5(){ String str = null; SEO靠我 Optional<String> opt = Optional.ofNullable(str); // System.out.println(opt.get());//SEO靠我java.util.NoSuchElementException: No value present } @Test public void test6SEO靠我(){ String str = "hello"; Optional<String> opt = Optional.ofNullable(str); SSEO靠我tring string = opt.orElse("atguigu"); System.out.println(string); } @Test SEO靠我 public void test7(){ String str = null; Optional<String> opt = Optional.ofNullSEO靠我able(str); String string = opt.orElseGet(String::new); System.out.println(string); SEO靠我 } @Test public void test8(){ String str = null; Optional<StriSEO靠我ng> opt = Optional.ofNullable(str); String string = opt.orElseThrow(()->new RuntimeExceptionSEO靠我("值不存在")); System.out.println(string); } @Test public void test9(){ SEO靠我 String str = "Hello1"; Optional<String> opt = Optional.ofNullable(str); //判断SEO靠我是否是纯字母单词,如果是,转为大写,否则保持不变 String result = opt.filter(s->s.matches("[a-zA-Z]+")) .map(SEO靠我s -> s.toUpperCase()).orElse(str); System.out.println(result); } }这是JDK9-11的SEO靠我新特性
新增方法描述新增的版本boolean isEmpty()判断value是否为空JDK 11ifPresentOrElse(Consumer<? super T> action, RunnableSEO靠我 emptyAction)value非空,执行参数1功能;如果value为空,执行参数2功能JDK 9Optional<T> or(Supplier<? extends Optional<? exteSEO靠我nds T>> supplier)value非空,返回对应的Optional;value为空,返回形参封装的OptionalJDK 9Stream<T> stream()value非空,返回仅包含此vSEO靠我alue的Stream;否则,返回一个空的StreamJDK 9T orElseThrow()value非空,返回value;否则抛异常NoSuchElementExceptionJDK 10这是JDK9的新特性。
产生背景:
Motivation The current implementation of the String class stores chaSEO靠我racters in a char array, using two bytes (sixteen bits) for each character. Data gathered from many SEO靠我different applications indicates that strings are a major component of heap usage and, moreover, thaSEO靠我t most String objects contain only Latin-1 characters. Such characters require only one byte of storSEO靠我age, hence half of the space in the internal char arrays of such String objects is going unused.
使用说明SEO靠我:
We propose to change the internal representation of the String class from a UTF-16 char SEO靠我array to a byte array plus an encoding-flag field. The new String class will store characters encodeSEO靠我d either as ISO-8859-1/Latin-1 (one byte per character), or as UTF-16 (two bytes per character), basSEO靠我ed upon the contents of the string. The encoding flag will indicate which encoding is used.
结论:StringSEO靠我 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标记,节约了一些空间。
public final class String implements java.io.SerSEO靠我ializable, Comparable<String>, CharSequence { @Stable private final byte[] value; SEO靠我 ... }拓展:StringBuffer 与 StringBuilder
那StringBuffer 和 StringBuilder 是否仍无动于衷呢?
String-relaSEO靠我ted classes such as AbstractStringBuilder, StringBuilder, and StringBuffer will be updated to use thSEO靠我e same representation, as will the HotSpot VMs intrinsic string operations.
JDK11新特性:新增了一系列字符串处理方法
描述举SEO靠我例判断字符串是否为空白" ".isBlank(); // true去除首尾空白" Javastack ".strip(); // "Javastack"去除尾部空格" Javastack ".striSEO靠我pTrailing(); // " Javastack"去除首部空格" Javastack ".stripLeading(); // "Javastack "复制字符串"Java".repeat(3)SEO靠我;// "JavaJavaJava"行数统计"A\nB\nC".lines().count(); // 3JDK12新特性:String 实现了 Constable 接口
String源码:
publicSEO靠我 final class String implements java.io.Serializable, Comparable<String>, CharSequence,Constable, ConSEO靠我stantDesc {java.lang.constant.Constable接口定义了抽象方法:
public interface Constable { Optional<? extSEO靠我ends ConstantDesc> describeConstable(); }Java 12 String 的实现源码:
/** * Returns an {@linSEO靠我k Optional} containing the nominal descriptor for this * instance, which is the instance itsSEO靠我elf. * * @return an {@link Optional} describing the {@linkplain String} instance SEO靠我 * @since 12 */ @Override public Optional<String> describeConstable() { SEO靠我 return Optional.of(this); }很简单,其实就是调用 Optional.of 方法返回一个 Optional 类型。
举例:
private statSEO靠我ic void testDescribeConstable() { String name = "尚硅谷Java高级工程师"; Optional<String> optSEO靠我ional = name.describeConstable(); System.out.println(optional.get()); }结果输出:
尚硅谷Java高SEO靠我级工程师JDK12新特性:String新增方法
String的transform(Function)
var result = "foo".transform(input -> input + " barSEO靠我"); System.out.println(result); //foo bar或者
var result = "foo".transform(input -> input + " bSEO靠我ar").transform(String::toUpperCase) System.out.println(result); //FOO BAR对应的源码:
/** *SEO靠我 This method allows the application of a function to {@code this} * string. The function shoSEO靠我uld expect a single String argument * and produce an {@code R} result. * @since 12 SEO靠我 */ public <R> R transform(Function<? super String, ? extends R> f) { return fSEO靠我.apply(this); }在某种情况下,该方法应该被称为map()。
举例:
private static void testTransform() { System.SEO靠我out.println("======test java 12 transform======"); List<String> list1 = List.of("Java", " PySEO靠我thon", " C++ "); List<String> list2 = new ArrayList<>(); list1.forEach(element -> liSEO靠我st2.add(element.transform(String::strip) .transform(String::toUpperCase) .transform(SEO靠我(e) -> "Hi," + e)) ); list2.forEach(System.out::println); }结果输出:
======test jSEO靠我ava 12 transform====== Hi,JAVA Hi,PYTHON Hi,C++如果使用Java 8的Stream特性,可以如下实现:
prSEO靠我ivate static void testTransform1() { System.out.println("======test before java 12 ======");SEO靠我 List<String> list1 = List.of("Java ", " Python", " C++ "); Stream<String> stringStSEO靠我ream = list1.stream().map(element -> element.strip()).map(String::toUpperCase).map(element -> "HelloSEO靠我," + element); List<String> list2 = stringStream.collect(Collectors.toList()); list2SEO靠我.forEach(System.out::println); }Applet API 提供了一种将 Java AWT/Swing 控件嵌SEO靠我入到浏览器网页中的方法。不过,目前 Applet 已经被淘汰。大部分人可能压根就没有用过 Applet。
Applet API 实际上是无用的,因为所有 Web 浏览器供应商都已删除或透露计划放弃对 JSEO靠我ava 浏览器插件的支持。Java 9 的时候,Applet API 已经被标记为过时,Java 17 的时候终于标记为删除了。
具体如下:
java.applet.Applet javaSEO靠我.applet.AppletStub java.applet.AppletContext java.applet.AudioClip javax.swiSEO靠我ng.JApplet java.beans.AppletInitializer在java 8 中,标识符可以SEO靠我独立使用“_”来命名:
String _ = "hello"; System.out.println(_);但是,在java 9 中规定“_”不再可以单独命名标识符了,如果使用,会报错:SEO靠我
看下面的代码。
// 编译 javac JavaStack.java // 运行 java JavaStack我SEO靠我们的认知里,要运行一个 Java 源代码必须先编译,再运行。而在 Java 11 版本中,通过一个 java 命令就直接搞定了,如下所示:
java JavaStack.java注意点:
执行源文件中的第SEO靠我一个类,第一个类必须包含主方法。
GC是Java主要优势之一。 然而,当GC停顿太长,就会开始影响应用的响应时间。随着现代系统中内存不断增长,用户和程序员希望JVM能够以高效的方式SEO靠我充分利用这些内存, 并且无需长时间的GC暂停时间。
8.3.1 G1 GC
JDK9以后默认的垃圾回收器是G1GC。
JDK10 : 为G1提供并行的Full GC
G1最大的亮点就是可以尽量的避免full SEO靠我gc。但毕竟是“尽量”,在有些情况下,G1就要进行full gc了,比如如果它无法足够快的回收内存的时候,它就会强制停止所有的应用线程然后清理。
在Java10之前,一个单线程版的标记-清除-压缩算法被SEO靠我用于full gc。为了尽量减少full gc带来的影响,在Java10中,就把之前的那个单线程版的标记-清除-压缩的full gc算法改成了支持多个线程同时full gc。这样也算是减少了full SEO靠我gc所带来的停顿,从而提高性能。
你可以通过-XX:ParallelGCThreads参数来指定用于并行GC的线程数。
JDK12:可中断的 G1 Mixed GC
JDK12:增强G1,自动返回未用堆内存SEO靠我给操作系统
8.3.2 Shenandoah GC
JDK12:Shenandoah GC:低停顿时间的GC
Shenandoah 垃圾回收器是 Red Hat 在 2014 年宣布进行的一项垃圾收集器研究SEO靠我项目 Pauseless GC 的实现,旨在针对 JVM 上的内存收回实现低停顿的需求。
据 Red Hat 研发 Shenandoah 团队对外宣称,Shenandoah 垃圾回收器的暂停时间与堆大小SEO靠我无关,这意味着无论将堆设置为 200 MB 还是 200 GB,都将拥有一致的系统暂停时间,不过实际使用性能将取决于实际工作堆的大小和工作负载。
Shenandoah GC 主要目标是 99.9% 的暂SEO靠我停小于 10ms,暂停与堆大小无关等。
这是一个实验性功能,不包含在默认(Oracle)的OpenJDK版本中。
Shenandoah开发团队在实际应用中的测试数据:
JDK15:Shenandoah垃圾回SEO靠我收算法转正
Shenandoah垃圾回收算法终于从实验特性转变为产品特性,这是一个从 JDK 12 引入的回收算法,该算法通过与正在运行的 Java 线程同时进行疏散工作来减少 GC 暂停时间。ShenSEO靠我andoah 的暂停时间与堆大小无关,无论堆栈是 200 MB 还是 200 GB,都具有相同的一致暂停时间。
Shenandoah在JDK12被作为experimental引入,在JDK15变为ProSEO靠我duction;之前需要通过-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC来启用,现在只需要-XX:+UseShenandoahGC即可启用SEO靠我
8.3.3 革命性的 ZGC
JDK11:引入革命性的 ZGC
ZGC,这应该是JDK11最为瞩目的特性,没有之一。
ZGC是一个并发、基于region、压缩型的垃圾收集器。
ZGC的设计目标是:支持TB级内SEO靠我存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于15%。 将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存),或压缩堆。
JDK13SEO靠我:ZGC:将未使用的堆内存归还给操作系统
JDK14:ZGC on macOS和windows
JDK14之前,ZGC仅Linux才支持。现在mac或Windows上也能使用ZGC了,示例如下:
-XX:+SEO靠我UnlockExperimentalVMOptions -XX:+UseZGCZGC与Shenandoah目标高度相似,在尽可能对吞吐量影响不大的前提下,实现在任意堆内存大小下都可以把垃圾收集的停顿时SEO靠我间限制在十毫秒以内的低延迟。
JDK15:ZGC 功能转正
ZGC是Java 11引入的新的垃圾收集器,经过了多个实验阶段,自此终于成为正式特性。
但是这并不是替换默认的GC,默认的GC仍然还是G1;之前需SEO靠我要通过-XX:+UnlockExperimentalVMOptions、-XX:+UseZGC来启用ZGC,现在只需要-XX:+UseZGC就可以。相信不久的将来它必将成为默认的垃圾回收器。
ZGC的性SEO靠我能已经相当亮眼,用“令人震惊、革命性”来形容,不为过。未来将成为服务端、大内存、低延迟应用的首选垃圾收集器。
怎么形容Shenandoah和ZGC的关系呢?异同点大概如下:
相同点:性能几乎可认为是相同的SEO靠我
不同点:ZGC是Oracle JDK的,根正苗红。而Shenandoah只存在于OpenJDK中,因此使用时需注意你的JDK版本
JDK16:ZGC 并发线程处理
在线程的堆栈处理过程中,总有一个制约因素SEO靠我就是safepoints。在safepoints这个点,Java的线程是要暂停执行的,从而限制了GC的效率。
回顾:
我们都知道,在之前,需要 GC 的时候,为了进行垃圾回收,需要所有的线程都暂停下来,这SEO靠我个暂停的时间我们称为Stop The World。
而为了实现 STW 这个操作, JVM 需要为每个线程选择一个点停止运行,这个点就叫做安全点(Safepoints)。
而ZGC的并发线程堆栈处理可以保SEO靠我证Java线程可以在GC safepoints的同时可以并发执行。它有助于提高所开发的Java软件应用程序的性能和效率。
随着云计算和 AI 等技术浪潮,当前的计算模式和场景正在发生翻天SEO靠我覆地的变化,不仅对 Java 的发展速度提出了更高要求,也深刻影响着 Java 技术的发展方向。传统的大型企业或互联网应用,正在被云端、容器化应用、模块化的微服务甚至是函数(FaaS, FunctioSEO靠我n-as-a-Service)所替代。
Java 需要在新的计算场景下,改进开发效率。比如,Java 代码虽然进行了一些类型推断等改进,更易用的集合 API 等,但仍然给开发者留下了过于刻板、形式主义的SEO靠我印象,这是一个长期的改进方向。
Java虽然标榜面向对象编程,却毫不顾忌的加入面向接口编程思想,又扯出匿名对象的概念,每增加一个新的东西,对Java的根本(面向对象思想)的一次冲击。
士,不可不弘毅,任重SEO靠我而道远。
网站备案号:浙ICP备17034767号-2