28.java中Java8.0的新特性(附讲解和练习)
Java 8新特性簡介
- 速度更快
- 代碼更少(增加了新的語法: Lambda 表達(dá)式)
- 強(qiáng)大的 Stream API
- 便于并行
- 最大化減少空指針異常: Optional
- Nashorn引擎,允許在JVM上運(yùn)行JS應(yīng)用
Lambda表達(dá)式(重要)(Lambda表達(dá)式就是一個(gè)函數(shù)式接口的實(shí)例)
Lambda 是一個(gè)匿名函數(shù),我們可以把 Lambda 表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞)。使用它可以寫出更簡潔、更靈活的代碼。作為一種更緊湊的代碼風(fēng)格,使Java的語言表達(dá)能力得到了提升。
Lambda表達(dá)式的使用
1.舉例: (o1,o2) -> Integer.compare(o1,o2);
2.格式:
- -> :lambda操作符 或 箭頭操作符
- ->左邊:lambda形參列表 (其實(shí)就是接口中的抽象方法的形參列表)
- ->右邊:lambda體 (其實(shí)就是重寫的抽象方法的方法體)
3.Lambda表達(dá)式的使用:(分為6種情況介紹)
總結(jié):
- ->左邊:lambda形參列表的參數(shù)類型可以省略(類型推斷);如果lambda形參列表只有一個(gè)參數(shù),其一對()也可以省略
- ->右邊:lambda體應(yīng)該使用一對{}包裹;如果lambda體只有一條執(zhí)行語句(可能是return語句),省略這一對{}和return關(guān)鍵字
4.Lambda表達(dá)式的本質(zhì):作為函數(shù)式接口的實(shí)例
5.如果一個(gè)接口中,只聲明了一個(gè)抽象方法,則此接口就稱為函數(shù)式接口。我們可以在一個(gè)接口上使用 @FunctionalInterface 注解,這樣做可以檢查它是否是一個(gè)函數(shù)式接口。
6. 所以以前用匿名實(shí)現(xiàn)類表示的現(xiàn)在都可以用Lambda表達(dá)式來寫。
下面展示一些 Lambda表達(dá)式的使用。
public class LambdaTest1 {//語法格式一:無參,無返回值@Testpublic void test1(){Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("我愛北京天安門");}};r1.run();System.out.println("***********************");Runnable r2 = () -> {System.out.println("我愛北京故宮");};r2.run();}//語法格式二:Lambda 需要一個(gè)參數(shù),但是沒有返回值。@Testpublic void test2(){Consumer<String> con = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};con.accept("謊言和誓言的區(qū)別是什么?");System.out.println("*******************");Consumer<String> con1 = (String s) -> {System.out.println(s);};con1.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");}//語法格式三:數(shù)據(jù)類型可以省略,因?yàn)榭捎删幾g器推斷得出,稱為“類型推斷”@Testpublic void test3(){Consumer<String> con1 = (String s) -> {System.out.println(s);};con1.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");System.out.println("*******************");Consumer<String> con2 = (s) -> {System.out.println(s);};con2.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");}@Testpublic void test4(){ArrayList<String> list = new ArrayList<>();//類型推斷int[] arr = {1,2,3};//類型推斷}//語法格式四:Lambda 若只需要一個(gè)參數(shù)時(shí),參數(shù)的小括號可以省略@Testpublic void test5(){Consumer<String> con1 = (s) -> {System.out.println(s);};con1.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");System.out.println("*******************");Consumer<String> con2 = s -> {System.out.println(s);};con2.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");}//語法格式五:Lambda 需要兩個(gè)或以上的參數(shù),多條執(zhí)行語句,并且可以有返回值@Testpublic void test6(){Comparator<Integer> com1 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);}};System.out.println(com1.compare(12,21));System.out.println("*****************************");Comparator<Integer> com2 = (o1,o2) -> {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);};System.out.println(com2.compare(12,6));}//語法格式六:當(dāng) Lambda 體只有一條語句時(shí),return 與大括號若有,都可以省略@Testpublic void test7(){Comparator<Integer> com1 = (o1,o2) -> {return o1.compareTo(o2);};System.out.println(com1.compare(12,6));System.out.println("*****************************");Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);System.out.println(com2.compare(12,21));}@Testpublic void test8(){Consumer<String> con1 = s -> {System.out.println(s);};con1.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");System.out.println("*****************************");Consumer<String> con2 = s -> System.out.println(s);con2.accept("一個(gè)是聽得人當(dāng)真了,一個(gè)是說的人當(dāng)真了");}}函數(shù)式(Functional)接口
函數(shù)式(Functional)接口
? 只包含一個(gè)抽象方法的接口,稱為函數(shù)式接口。(Lambda表達(dá)式使用的前提)
? 你可以通過 Lambda 表達(dá)式來創(chuàng)建該接口的對象。(若 Lambda 表達(dá)式拋出一個(gè)受檢異常(即:非運(yùn)行時(shí)異常),那么該異常需要在目標(biāo)接口的抽象方法上進(jìn)行聲明)。
? 我們可以在一個(gè)接口上使用 @FunctionalInterface 注解,這樣做可以檢查它是否是一個(gè)函數(shù)式接口。同時(shí) javadoc 也會包含一條聲明,說明這個(gè)接口是一個(gè)函數(shù)式接口。
? 在java.util.function包下定義了Java 8 的豐富的函數(shù)式接口
下面展示一些 數(shù)據(jù)測試。
public class Employee {private int id;private String name;private int age;private double salary;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public Employee() {System.out.println("Employee().....");}public Employee(int id) {this.id = id;System.out.println("Employee(int id).....");}public Employee(int id, String name) {this.id = id;this.name = name;}public Employee(int id, String name, int age, double salary) {this.id = id;this.name = name;this.age = age;this.salary = salary;}@Overridepublic String toString() {return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';}@Overridepublic boolean equals(Object o) {if (this == o)return true;if (o == null || getClass() != o.getClass())return false;Employee employee = (Employee) o;if (id != employee.id)return false;if (age != employee.age)return false;if (Double.compare(employee.salary, salary) != 0)return false;return name != null ? name.equals(employee.name) : employee.name == null;}@Overridepublic int hashCode() {int result;long temp;result = id;result = 31 * result + (name != null ? name.hashCode() : 0);result = 31 * result + age;temp = Double.doubleToLongBits(salary);result = 31 * result + (int) (temp ^ (temp >>> 32));return result;} }下面展示一些 提供用于測試的數(shù)據(jù)。
public class EmployeeData {public static List<Employee> getEmployees(){List<Employee> list = new ArrayList<>();list.add(new Employee(1001, "馬化騰", 34, 6000.38));list.add(new Employee(1002, "馬云", 12, 9876.12));list.add(new Employee(1003, "劉強(qiáng)東", 33, 3000.82));list.add(new Employee(1004, "雷軍", 26, 7657.37));list.add(new Employee(1005, "李彥宏", 65, 5555.32));list.add(new Employee(1006, "比爾蓋茨", 42, 9500.43));list.add(new Employee(1007, "任正非", 26, 4333.32));list.add(new Employee(1008, "扎克伯格", 35, 2500.32));return list;}}
下面展示一些 Java內(nèi)置的4大核心函數(shù)式接口。
方法引用與構(gòu)造器引用
方法引用(Method References)
? 當(dāng)要傳遞給Lambda體的操作,已經(jīng)有實(shí)現(xiàn)的方法了,可以使用方法引用!
? 方法引用可以看做是Lambda表達(dá)式深層次的表達(dá)。換句話說,方法引用就是Lambda表達(dá)式,也就是函數(shù)式接口的一個(gè)實(shí)例,通過方法的名字來指向一個(gè)方法,可以認(rèn)為是Lambda表達(dá)式的一個(gè)語法糖。
? 要求: 實(shí)現(xiàn)接口的抽象方法的參數(shù)列表和返回值類型,必須與方法引用的方法的參數(shù)列表和返回值類型保持一致!
? 格式: 使用操作符 “::” 將類(或?qū)ο? 與 方法名分隔開來。
? 如下三種主要使用情況:
- 對象::實(shí)例方法名
- 類::靜態(tài)方法名
- 類::實(shí)例方法名
下面展示一些 方法引用(Method References)。
/*** 方法引用的使用** 1.使用情境:當(dāng)要傳遞給Lambda體的操作,已經(jīng)有實(shí)現(xiàn)的方法了,可以使用方法引用!** 2.方法引用,本質(zhì)上就是Lambda表達(dá)式,而Lambda表達(dá)式作為函數(shù)式接口的實(shí)例。所以* 方法引用,也是函數(shù)式接口的實(shí)例。** 3. 使用格式: 類(或?qū)ο? :: 方法名** 4. 具體分為如下的三種情況:* 情況1 對象 :: 非靜態(tài)方法* 情況2 類 :: 靜態(tài)方法** 情況3 類 :: 非靜態(tài)方法** 5. 方法引用使用的要求:要求接口中的抽象方法的形參列表和返回值類型與方法引用的方法的* 形參列表和返回值類型相同!(針對于情況1和情況2)** Created by shkstart.*/ public class MethodRefTest {// 情況一:對象 :: 實(shí)例方法//Consumer中的void accept(T t)//PrintStream中的void println(T t)@Testpublic void test1() {Consumer<String> con1 = str -> System.out.println(str);con1.accept("北京");System.out.println("*******************");PrintStream ps = System.out;Consumer<String> con2 = ps::println;con2.accept("beijing");}//Supplier中的T get()//Employee中的String getName()@Testpublic void test2() {Employee emp = new Employee(1001,"Tom",23,5600);Supplier<String> sup1 = () -> emp.getName();System.out.println(sup1.get());System.out.println("*******************");Supplier<String> sup2 = emp::getName;System.out.println(sup2.get());}// 情況二:類 :: 靜態(tài)方法//Comparator中的int compare(T t1,T t2)//Integer中的int compare(T t1,T t2)@Testpublic void test3() {Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);System.out.println(com1.compare(12,21));System.out.println("*******************");Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(12,3));}//Function中的R apply(T t)//Math中的Long round(Double d)@Testpublic void test4() {Function<Double,Long> func = new Function<Double, Long>() {@Overridepublic Long apply(Double d) {return Math.round(d);}};System.out.println("*******************");Function<Double,Long> func1 = d -> Math.round(d);System.out.println(func1.apply(12.3));System.out.println("*******************");Function<Double,Long> func2 = Math::round;System.out.println(func2.apply(12.6));}// 情況三:類 :: 實(shí)例方法 (有難度)// Comparator中的int comapre(T t1,T t2)// String中的int t1.compareTo(t2)@Testpublic void test5() {Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc","abd"));System.out.println("*******************");Comparator<String> com2 = String :: compareTo;System.out.println(com2.compare("abd","abm"));}//BiPredicate中的boolean test(T t1, T t2);//String中的boolean t1.equals(t2)@Testpublic void test6() {BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);System.out.println(pre1.test("abc","abc"));System.out.println("*******************");BiPredicate<String,String> pre2 = String :: equals;System.out.println(pre2.test("abc","abd"));}// Function中的R apply(T t)// Employee中的String getName();@Testpublic void test7() {Employee employee = new Employee(1001, "Jerry", 23, 6000);Function<Employee,String> func1 = e -> e.getName();System.out.println(func1.apply(employee));System.out.println("*******************");Function<Employee,String> func2 = Employee::getName;System.out.println(func2.apply(employee));}}構(gòu)造器引用
格式: ClassName::new
與函數(shù)式接口相結(jié)合,自動(dòng)與函數(shù)式接口中方法兼容。可以把構(gòu)造器引用賦值給定義的方法,要求構(gòu)造器參數(shù)列表要與接口中抽象方法的參數(shù)列表一致!且方法的返回值即為構(gòu)造器對應(yīng)類的對象。
下面展示一些 構(gòu)造器引用。
/*** 一、構(gòu)造器引用* 和方法引用類似,函數(shù)式接口的抽象方法的形參列表和構(gòu)造器的形參列表一致。* 抽象方法的返回值類型即為構(gòu)造器所屬的類的類型*** Created by shkstart*/ public class ConstructorRefTest {//構(gòu)造器引用//Supplier中的T get()//Employee的空參構(gòu)造器:Employee()@Testpublic void test1(){Supplier<Employee> sup = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};System.out.println("*******************");Supplier<Employee> sup1 = () -> new Employee();System.out.println(sup1.get());System.out.println("*******************");Supplier<Employee> sup2 = Employee :: new;System.out.println(sup2.get());}//Function中的R apply(T t)@Testpublic void test2(){Function<Integer,Employee> func1 = id -> new Employee(id);Employee employee = func1.apply(1001);System.out.println(employee);System.out.println("*******************");Function<Integer,Employee> func2 = Employee :: new;Employee employee1 = func2.apply(1002);System.out.println(employee1);}//BiFunction中的R apply(T t,U u)@Testpublic void test3(){BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);System.out.println(func1.apply(1001,"Tom"));System.out.println("*******************");BiFunction<Integer,String,Employee> func2 = Employee :: new;System.out.println(func2.apply(1002,"Tom"));} }數(shù)組引用
格式: type[] :: new
大家可以把數(shù)組看做是一個(gè)特殊的類,則寫法與構(gòu)造器引用一致。
下面展示一些 數(shù)組引用。
//數(shù)組引用//Function中的R apply(T t)@Testpublic void test4(){Function<Integer,String[]> func1 = length -> new String[length];String[] arr1 = func1.apply(5);System.out.println(Arrays.toString(arr1));System.out.println("*******************");Function<Integer,String[]> func2 = String[] :: new;String[] arr2 = func2.apply(10);System.out.println(Arrays.toString(arr2));} var foo = 'bar';強(qiáng)大的Stream API(重要)
Stream API說明
使用Stream API 對集合數(shù)據(jù)進(jìn)行操作,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作。 Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
Stream 和 Collection 集合的區(qū)別: Collection 是一種靜態(tài)的內(nèi)存數(shù)據(jù)結(jié)構(gòu),而 Stream 是有關(guān)計(jì)算的。 前者是主要面向內(nèi)存,存儲在內(nèi)存中,后者主要是面向 CPU,通過 CPU 實(shí)現(xiàn)計(jì)算。
注意:
①Stream 自己不會存儲元素。
②Stream 不會改變源對象。相反,他們會返回一個(gè)持有結(jié)果的新Stream。
③Stream 操作是延遲執(zhí)行的。這意味著他們會等到需要結(jié)果的時(shí)候才執(zhí)行。
Stream 的操作三個(gè)步驟
1- 創(chuàng)建 Stream一個(gè)數(shù)據(jù)源(如:集合、數(shù)組),獲取一個(gè)流
2- 中間操作: 一個(gè)中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理
3- 終止操作(終端操作) :一旦執(zhí)行終止操作, 就執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果。之后,不會再被使用
創(chuàng)建 Stream方式一:通過集合
Java8 中的 Collection 接口被擴(kuò)展,提供了兩個(gè)獲取流的方法:
? default Stream stream() : 返回一個(gè)順序流
? default Stream parallelStream() : 返回一個(gè)并行流
創(chuàng)建 Stream方式二:通過數(shù)組
Java8 中的 Arrays 的靜態(tài)方法 stream() 可以獲取數(shù)組流:
? static Stream stream(T[] array): 返回一個(gè)流
重載形式,能夠處理對應(yīng)基本類型的數(shù)組:
? public static IntStream stream(int[] array)
? public static LongStream stream(long[] array)
? public static DoubleStream stream(double[] array)
創(chuàng)建 Stream方式三:通過Stream的of()
可以調(diào)用Stream類靜態(tài)方法 of(), 通過顯示值創(chuàng)建一個(gè)流。它可以接收任意數(shù)量的參數(shù)。
? public static Stream of(T… values) : 返回一個(gè)流
創(chuàng)建 Stream方式四:創(chuàng)建無限流
可以使用靜態(tài)方法 Stream.iterate() 和 Stream.generate(),創(chuàng)建無限流。
? 迭代
public static Stream iterate(final T seed, final UnaryOperator f)
? 生成
public static Stream generate(Supplier s)
下面展示一些 創(chuàng)建 Stream一個(gè)數(shù)據(jù)源(如:集合、數(shù)組)即Stream的實(shí)例化。
public class StreamAPITest {//創(chuàng)建 Stream方式一:通過集合@Testpublic void test1(){List<Employee> employees = EmployeeData.getEmployees();// default Stream<E> stream() : 返回一個(gè)順序流Stream<Employee> stream = employees.stream();// default Stream<E> parallelStream() : 返回一個(gè)并行流Stream<Employee> parallelStream = employees.parallelStream();}//創(chuàng)建 Stream方式二:通過數(shù)組@Testpublic void test2(){int[] arr = new int[]{1,2,3,4,5,6};//調(diào)用Arrays類的static <T> Stream<T> stream(T[] array): 返回一個(gè)流IntStream stream = Arrays.stream(arr);Employee e1 = new Employee(1001,"Tom");Employee e2 = new Employee(1002,"Jerry");Employee[] arr1 = new Employee[]{e1,e2};Stream<Employee> stream1 = Arrays.stream(arr1);}//創(chuàng)建 Stream方式三:通過Stream的of()@Testpublic void test3(){Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);}//創(chuàng)建 Stream方式四:創(chuàng)建無限流@Testpublic void test4(){// 迭代 // public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)//遍歷前10個(gè)偶數(shù)Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);// 生成 // public static<T> Stream<T> generate(Supplier<T> s)Stream.generate(Math::random).limit(10).forEach(System.out::println);}}Stream 的中間操作
多個(gè)中間操作可以連接起來形成一個(gè)流水線,除非流水線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何的處理!而在終止操作時(shí)一次性全部處理,稱為“惰性求值” 。
1-篩選與切片
下面展示一些 篩選與切片。
2-映 射
下面展示一些 映射。
3-排序
下面展示一些 排序。
Stream 的終止操作
? 終端操作會從流的流水線生成結(jié)果。其結(jié)果可以是任何不是流的值,例如: List、 Integer,甚至是 void 。
? 流進(jìn)行了終止操作后,不能再次使用。
1-匹配與查找
下面展示一些 匹配與查找。
2-歸約
備注: map 和 reduce 的連接通常稱為 map-reduce 模式,因 Google用它來進(jìn)行網(wǎng)絡(luò)搜索而出名。
下面展示一些 歸約。
3-收集
Collector 接口中方法的實(shí)現(xiàn)決定了如何對流執(zhí)行收集的操作(如收集到 List、 Set、Map)。
另外, Collectors 實(shí)用類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見收集器實(shí)例,具體方法與實(shí)例如下表:
下面展示一些 收集。
Optional類
? Optional提供很多有用的方法,這樣我們就不用顯式進(jìn)行空值檢測。
? 創(chuàng)建Optional類對象的方法:
- Optional.of(T t) : 創(chuàng)建一個(gè) Optional 實(shí)例, t必須非空;
- Optional.empty() : 創(chuàng)建一個(gè)空的 Optional 實(shí)例
- Optional.ofNullable(T t): t可以為null
? 判斷Optional容器中是否包含對象:
- boolean isPresent() : 判斷是否包含對象
- void ifPresent(Consumer<? super T> consumer) : 如果有值,就執(zhí)行Consumer接口的實(shí)現(xiàn)代碼,并且該值會作為參數(shù)傳給它。
? 獲取Optional容器的對象:
- T get(): 如果調(diào)用對象包含值,返回該值,否則拋異常
- T orElse(T other) : 如果有值則將其返回,否則返回指定的other對象。
- T orElseGet(Supplier<? extends T> other) : 如果有值則將其返回,否則返回由Supplier接口實(shí)現(xiàn)提供的對象。
- T orElseThrow(Supplier<? extends X> exceptionSupplier) : 如果有值則將其返回,否則拋出由Supplier接口實(shí)現(xiàn)提供的異常。
下面展示一些 測試數(shù)據(jù)一。
public class Boy {private Girl girl;@Overridepublic String toString() {return "Boy{" +"girl=" + girl +'}';}public Girl getGirl() {return girl;}public void setGirl(Girl girl) {this.girl = girl;}public Boy() {}public Boy(Girl girl) {this.girl = girl;} }下面展示一些 測試數(shù)據(jù)二。
public class Girl {private String name;@Overridepublic String toString() {return "Girl{" +"name='" + name + '\'' +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public Girl() {}public Girl(String name) {this.name = name;} }下面展示一些 Optional類的使用。
public class OptionalTest {/* Optional.of(T t) : 創(chuàng)建一個(gè) Optional 實(shí)例,t必須非空; Optional.empty() : 創(chuàng)建一個(gè)空的 Optional 實(shí)例 Optional.ofNullable(T t):t可以為null*/@Testpublic void test1(){Girl girl = new Girl(); // girl = null;//of(T t):保證t是非空的Optional<Girl> optionalGirl = Optional.of(girl);}@Testpublic void test2(){Girl girl = new Girl(); // girl = null;//ofNullable(T t):t可以為nullOptional<Girl> optionalGirl = Optional.ofNullable(girl);System.out.println(optionalGirl);//orElse(T t1):如果單前的Optional內(nèi)部封裝的t是非空的,則返回內(nèi)部的t.//如果內(nèi)部的t是空的,則返回orElse()方法中的參數(shù)t1.Girl girl1 = optionalGirl.orElse(new Girl("趙麗穎"));System.out.println(girl1);}public String getGirlName(Boy boy){return boy.getGirl().getName();}@Testpublic void test3(){Boy boy = new Boy();boy = null;String girlName = getGirlName(boy);System.out.println(girlName);}//優(yōu)化以后的getGirlName():public String getGirlName1(Boy boy){if(boy != null){Girl girl = boy.getGirl();if(girl != null){return girl.getName();}}return null;}@Testpublic void test4(){Boy boy = new Boy();boy = null;String girlName = getGirlName1(boy);System.out.println(girlName);}//使用Optional類的getGirlName():public String getGirlName2(Boy boy){Optional<Boy> boyOptional = Optional.ofNullable(boy);//此時(shí)的boy1一定非空Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪麗熱巴")));Girl girl = boy1.getGirl();Optional<Girl> girlOptional = Optional.ofNullable(girl);//girl1一定非空Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));return girl1.getName();}@Testpublic void test5(){Boy boy = null;boy = new Boy();boy = new Boy(new Girl("蒼老師"));String girlName = getGirlName2(boy);System.out.println(girlName);}}總結(jié)
以上是生活随笔為你收集整理的28.java中Java8.0的新特性(附讲解和练习)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis使用过程出现类型转换异常问题-
- 下一篇: hackerrank Java Data