JDK1.8新特性1
- JDK1.8新特性:
- Lambda表達式:
- 使用:
- 無參數無返回值:
- 單參數無返回值:
- 多參數無返回值:
- 多參數有返回值:
- 案例:
- 案例1:
- 案例2:
- 案例3:
- 函數式接口:
- 四大核心函數式接口:
- 衍生接口:
- 使用:
- 使用1:
- 使用2:
- 方法、構造方法和數組引用:
- 方法引用:
- 對象::實例方法
- 類名::靜態方法
- 類名::實例方法
- 構造方法引用:
- 數組引用:
JDK1.8新特性:
- 速度更快 - 優化底層源碼,比如HashMap、ConcurrentHashMap。
- 代碼更少 - 添加新的語法Lambda表達式。
- 強大的Stream API。
- 便于并行。
- 最大化減少空指針異常 - Optional。
?
?
Lambda表達式:
Lambda是一個匿名函數(方法), 允許把函數作為一個方法的參數 。
?
作用:? ? ? ? ?1. 一般都是優化匿名內部類。
? ? ? ? ?2. 利用Lambda表達式可以寫出更簡潔、更靈活的代碼。
?
使用:
tips:
- 重寫方法的形參只有一個時,可以不加小括號。
- Lambda表達式當中不允許聲明一個與局部變量同名的參數或者局部變量。
- Lambda表達式中訪問外層的局部變量,外層的局部變量自動變成隱式常量,默認添加final。
- 重寫方法的形參同時加類型或同時不加類型。
?
無參數無返回值:
當匿名內部類中只有一個方法時。
public interface I1 {public void method();
}
public class Test01 {public static void main(String[] args) {I1 i1 = new I1() {@Overridepublic void method() {System.out.println("使用傳統匿名內部類的方式");}};i1.method();//當匿名內部類中只有一個方法時,才能使用lambda表達式這樣簡化。I1 i2 = ()->{System.out.println("使用lambda表達式的方式");};i2.method();//當匿名內部類中只有一個方法時,才能使用lambda表達式這樣簡化。I1 i3 = ()->System.out.println("使用lambda表達式的方式");i3.method();}
}
?
?
單參數無返回值:
當匿名內部類中只有一個方法,且該方法只有一個參數。
public interface I1 {public void method(String str);
}
public class Test01 {public static void main(String[] args) {I1 i1 = new I1() {@Overridepublic void method(String str) {System.out.println("使用傳統匿名內部類的方式:" + str);}};i1.method("今天天氣真好!");I1 i2 = (String str)->{System.out.println("使用lambda表達式的方式:" + str);};i2.method("今天天氣真好!");I1 i3 = (String str)->System.out.println("使用lambda表達式的方式:" + str);i3.method("今天天氣真好!");//省略參數的數據類型I1 i3 = (str)->System.out.println("使用lambda表達式的方式:" + str);i3.method("今天天氣真好!");//省略方法的小括號//方法的形參只有一個時,可以不加小括號。I1 i4 = str->System.out.println("使用lambda表達式的方式:" + str);i4.method("今天天氣真好!");}
}
?
?
多參數無返回值:
當匿名內部類中只有一個方法,且該方法只有多個參數。
public interface I1 {public void method(String str,int i);
}
public class Test01 {public static void main(String[] args) {I1 i1 = new I1() {@Overridepublic void method(String str, int i) {System.out.println("使用傳統匿名內部類的方式:" + str + " -- " + i);}};i1.method("今天天氣真好!", 666);I1 i2 = (String str,int i)->{System.out.println("使用lambda表達式的方式:" + str + " -- " + i);};i2.method("今天天氣真好!", 777);I1 i3 = (String str,int i)->System.out.println("使用lambda表達式的方式:" + str + " -- " + i);i3.method("今天天氣真好!", 888);//多個參數時,參數的數據類型要么全部去掉,要么全部保留。I1 i4 = (str, i)->System.out.println("使用lambda表達式的方式:" + str + " -- " + i);i4.method("今天天氣真好!", 999);}
}
多個參數時,參數的數據類型要么全部去掉,要么全部保留。
?
?
多參數有返回值:
當匿名內部類中只有一個方法,且該方法只有多個參數,且有返回值時。
public interface I1 {public String method(int a,int b);
}
public class Test01 {public static void main(String[] args) {I1 i1 = new I1() {@Overridepublic String method(int a, int b) {return "使用傳統匿名內部類的方式:" + (a+b);}};String method = i1.method(10, 10);System.out.println(method);I1 i2 = (int a,int b)->{return "使用lambda表達式的方式:" + (a+b);};String method = i2.method(20, 20);System.out.println(method);I1 i3 = (a, b)-> "使用lambda表達式的方式:" + (a+b);String method = i3.method(30, 30);System.out.println(method);}
}
?
?
案例:
案例1:
調用Collections.sort()方法,通過定制排序比較兩個Student對象(先按年齡比較,年齡相同按照薪資比較),使用Lambda表達式作為參數傳遞。
//枚舉
public enum Course {JAVA,HTML,PYTHON;
}
public class Student {private String name;private int age;private double salary;private Course course;public Student() {}public Student(String name, int age, double salary, Course course) {this.name = name;this.age = age;this.salary = salary;this.course = course;}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;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((course == null) ? 0 : course.hashCode());result = prime * result + ((name == null) ? 0 : name.hashCode());long temp;temp = Double.doubleToLongBits(salary);result = prime * result + (int) (temp ^ (temp >>> 32));return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Student other = (Student) obj;if (age != other.age)return false;if (course != other.course)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))return false;return true;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("Student [name=");builder.append(name);builder.append(", age=");builder.append(age);builder.append(", salary=");builder.append(salary);builder.append(", course=");builder.append(course);builder.append("]");return builder.toString();}}
public static void main(String[] args) {List<Student> stuList = Arrays.asList(new Student("張三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("趙六", 42, 6100,Course.HTML),new Student("孫七", 23, 9600,Course.PYTHON),new Student("吳八", 28, 3000,Course.PYTHON));//匿名內部類的方式
// Collections.sort(stuList, new Comparator<Student>() {
// @Override
// public int compare(Student o1, Student o2) {
// if(o1.equals(o2)){
// return 0;
// }
//
// int compare = Integer.compare(o1.getAge(), o2.getAge());
// if(compare != 0){
// return compare;
// }
//
// return Double.compare(o1.getSalary(), o2.getSalary());
// }
// });Collections.sort(stuList, (o1,o2)->{if(o1.equals(o2)){return 0;}int compare = Integer.compare(o1.getAge(), o2.getAge());if(compare != 0){return compare;}return Double.compare(o1.getSalary(), o2.getSalary());});for (Student stu : stuList) {System.out.println(stu);}}
?
?
案例2:
創建I1接口,創建抽象方法:public String getValue(String str),在測試類中編寫方法使用接口作為參數,將一個字符串轉為大寫,并作為方法的返回值。
public class Test01 {public static void main(String[] args) {String str = method("abc", (x)-> {return x.toUpperCase();});System.out.println(str);}public static String method(String str,I1 i1){return i1.getValue(str);}
}interface I1{public String getValue(String str);
}
?
?
案例3:
創建I1<T,R>接口,泛型T為參數,R為返回值,創建抽象方法:public R add(T t1,T t2),在測試類中編寫方法使用接口作為參數,計算兩個long類型的和。
public class Test01 {public static void main(String[] args) {long addLong = addLong(100,200,(a,b)->{return a+b;});System.out.println(addLong);}public static long addLong(long l1,long l2,I1<Long,Long> i1){return i1.add(l1, l2);}
}interface I1<T,R>{public R add(T t1,T t2);
}
?
?
?
函數式接口:
? 函數式接口:是指僅僅只包含一個抽象方法的接口,jdk1.8提供了一個@FunctionalInterface注解來定義函數式接口,如果我們定義的接口不符合函數式的規范便會報錯。配合Lambda表達式一起使用。
?
?
四大核心函數式接口:
? 應用場景:當項目中需要一個接口,并且該接口中只有一個抽象方法,就沒必要去創建新的接口,直接選擇Java提供的使用合適的函數式接口即可。
函數式接口 | 參數類型 | 返回類型 | 用途 |
---|---|---|---|
Consumer 消費型接口 | T | void | void accept(T t); |
Supplier 供給型接口 | void | T | T get(); |
Function<T, R> 函數型接口 | T | R | R apply(T t); |
Predicate 斷言型接口 | T | boolean | booelan test(T t); |
?
衍生接口:
函數式接口 | 參數類型 | 返回類型 | 用途 |
---|---|---|---|
BiConsumer<T, U> | T,U | void | 對類型為T,U參數應用操作。包含方法為void accept(T t,U u); |
BiFunction<T, U, R> | T,U | R | 對類型為T,U參數應用操作,并返回R類型的結果。包含方法為R apply(T t,U u); |
UnaryOperator extends Function<T, T> | T | T | 對類型為T的對象進行一元運算,并返回T類型的結果。包含方法為T apply(T t); |
BinaryOperator extends BiFunction<T,T,T> | T,T | T | 對類型為T的對象進行二元運算,并返回T類型的結果。包含方法為T apply(T t1,T t2); |
ToIntFunction ToLongFunction ToDoubleFunction | T | int long double | 分別計算int、long、double值的函數 |
IntFunction LongFunction DoubleFunction | int long double | R | 參數為int、long、double類型的函數 |
?
?
?
使用:
使用1:
創建I1接口,創建抽象方法:public String getValue(String str),在測試類中編寫方法使用接口作為參數,將一個字符串轉為大寫,并作為方法的返回值。
public class Test01 {public static void main(String[] args) {String str = method("abc", (x)-> {return x.toUpperCase();});System.out.println(str);}//Function函數式接口public static String method(String str,Function<String, String> fun){//apply函數式接口的方法return fun.apply(str);}
}
?
?
再更新:
public class Test01 {public static void main(String[] args) {String str = method("abc", (x)->{return x.toUpperCase();});System.out.println(str);}//UnaryOperator函數式接口public static String method(String str,UnaryOperator<String> uo){apply函數式接口的方法return uo.apply(str);}
}
?
?
?
使用2:
創建I1<T,R>接口,泛型T為參數,R為返回值,創建抽象方法:public R add(T t1,T t2),在測試類中編寫方法使用接口作為參數,計算兩個long類型的和。
public class Test01 {public static void main(String[] args) {long addLong = addLong(100,200,(a,b)->{return a+b;});System.out.println(addLong);}public static long addLong(long l1,long l2,BiFunction<Long,Long,Long> bf){return bf.apply(l1, l2);}
}
?
?
再更新:
public class Test01 {public static void main(String[] args) {long addLong = addLong(100,200,(a,b)->{return a+b;});System.out.println(addLong);}public static long addLong(long l1,long l2,BinaryOperator<Long> bo){return bo.apply(l1, l2);}
}
?
?
?
方法、構造方法和數組引用:
方法、構造方法和數組引用就是Lambda的另一種表現形式,可以簡化Lambda表達式。
?
?
方法引用:
若Lamdba表達式中的內容由方法已經實現了,可以使用方法引用這個技能,當你需要使用方法引用時,目標引用放在分隔符::前,方法的名稱放在后面。
?
對象::實例方法
Lambda表達式中調用方法的參數類型和返回值必須和函數式接口中的抽象方法一致。
public class Test01 {public static void main(String[] args) {I1 i1 = new I1() {@Overridepublic void method(String str) {//println方法無返回值,一個參數,參數類型是StringSystem.out.println(str);}};i1.method("今天天氣真好!");I1 i2 = (str)->System.out.println(str);i2.method("今天天氣真好!");// 因為 method方法無返回值,一個參數,參數類型是String,//且println方法無返回值,一個參數,參數類型是String//故可以使用方法的引用I1 i3 = System.out::println;i3.method("今天天氣真好!");}
}interface I1{//method無返回值,一個參數,參數類型是Stringpublic void method(String str);
}
因為 method 方法無返回值,一個參數,參數類型是 String ,且 println 方法無返回值,一個參數,參數類型是 String ,一 一對應,故可以使用方法的引用。
?
?
類名::靜態方法
Lambda表達式中調用方法的參數類型和返回值必須和函數式接口中的抽象方法一致。
public class Test01 {public static void main(String[] args) {Comparator<Integer> comparator = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1, o2);}};int compare1 = comparator.compare(10, 20);System.out.println(compare1);Comparator<Integer> comparator = (o1,o2)-> Integer.compare(o1, o2);int compare2 = comparator.compare(10, 20);System.out.println(compare2);Comparator<Integer> comparator = Integer::compare;int compare3 = comparator.compare(10, 20);System.out.println(compare3);}
}
?
?
類名::實例方法
? Lambda表達式參數列表中第一個參數必須是實例方法的調用者,第二個參數必須是實例方法的參數。
public class Test01 {public static void main(String[] args) {I1<String> i1 = new I1<String>() {@Overridepublic boolean method(String t1, String t2) {return t1.equals(t2);}};boolean method = i1.method("abc", "abc");System.out.println(method);I1<String> i2 = (str1,str2)->str1.equals(str2);boolean method2 = i2.method("abc", "abc");System.out.println(method2);//重寫method方法,該方法的第一個參數調用equals,第二個參數是傳入equals里的數據I1<String> i3 = String::equals;boolean method3 = i3.method("abc", "abc");System.out.println(method3);}
}interface I1<T>{public boolean method(T t1,T t2);
}
?
?
構造方法引用:
類名::new
需要調用的構造方法的參數列表必須和函數式接口中抽象方法的參數列表一致。
public class Test01 {public static void main(String[] args) {I1 i = new I1() {@Overridepublic Student method() {return new Student();}};Student st = i.method();System.out.println(st);//調用無參構造去創建學生對象//I1的method方法無參數I1 i1 = Student::new;Student stu1 = i1.method();System.out.println(stu1);//調用有參構造去創建學生對象//I2的method方法有參數I2 i2 = Student::new;Student stu2 = i2.method("小明", 23, 12000, Course.JAVA);System.out.println(stu2);}
}
interface I1{public Student method();
}
interface I2{public Student method(String name, int age, double salary, Course course);
}
?
?
數組引用:
type[]::new
public class Test01 {public static void main(String[] args) {//參數 方法里面的語句I1<String[]> i = (capacity)->new String[capacity];String[] s = i.method(3);System.out.println(Arrays.toString(s));I1<String[]> i1 = String[]::new;String[] ss = i1.method(3);System.out.println(Arrays.toString(ss));}
}interface I1<T>{public T method(int capacity);
}