【Java】jdk1.8新特性及用法總結
Java8新特性及用法總結
1. 介面中的實現方法
① 使用 default 關鍵字就可以給介面增加一個非抽象的方法實現;
② 介面還可以存在 static 靜態方法實現,使用 介面名.靜態方法名 的形式直接呼叫;
包括宣告@FunctionalInterface限制介面只有1個抽象方法時,也可以增加①或②。
程式碼示例:
public class TestInterface {
public static void main(String[] args) {
TestInter ti = new TestInter() {
@Override
public void m1() {
System.out.println("m1():匿名內部類實現該介面,只需要覆蓋m1()");
}
};
ti.m1();
ti.m2();
TestInter.m3();
}
}
/**
* 介面
* 測試Java8新特性,default和static在介面中定義的場景
* @FunctionalInterface 宣告為函式式介面,只能有 1 個公開抽象方法
*/
@FunctionalInterface
interface TestInter {
void m1(); // 公開抽象方法
default void m2() {
System.out.println("m2():default修飾的方法實現,在介面中...");
}
public static void m3() {
System.out.println("m3():static修飾的方法實現,在介面中...");
}
}
2. Lambda 表示式
概念:允許把函式作為一個方法的引數,程式碼簡潔緊湊(函式作為引數傳遞到方法中)
語法:
函式式介面 變數名 = (引數1,引數2...)->{
//方法體
};
新的操作符:-> (箭頭操作符)
- 箭頭操作符左側 (引數1,引數2,…)-> 表示引數列表
- 箭頭操作符右側 ->{…} 表示方法體
Lambda 表示式特點:
- 形參列表的資料型別會自動推斷
- 如果形參列表為空,只需保留()
- 如果形參列表只有1個引數,可以省略(),只要引數名字即可
- 如果執行語句只有1句,且無返回值,{}可以省略
- 若有返回值,仍想省略{},return也省略,必須保證執行語句為1句
- Lambda表示式不會生成單獨的內部類.class檔案
- Lambda表示式訪問區域性變數時,變數要修飾為 final,如果沒加會隱式自動新增
示例程式碼:
public class TestBasicLambda {
public static void main(String[] args) {
// 普通方式
List<String> list1 = Arrays.asList("aaa", "ddd", "ccc", "bbb");
list1.sort(new Comparator<String>() {
@Override // 按首字元排序規則
public int compare(String o1, String o2) {
return o1.charAt(0) > o2.charAt(0) ? 1 : -1;
}
});
System.out.println(list1); // aaa bbb ccc ddd
// Lambda表示式方式:實現介面中唯一1個方法的匿名內部類
List<String> list2 = Arrays.asList("aaa", "ddd", "ccc", "bbb");
list2.sort( (s1, s2)->{ return s1.charAt(0)>s2.charAt(0) ? 1 : -1; });
System.out.println(list2); // aaa bbb ccc ddd
}
}
3. 方法引用 ::
Lambda表示式的一種簡寫形式。
如果Lambda表示式方法體中只是呼叫一個特定的已存在的方法,則可以使用方法引用。
使用 :: 操作符將物件或類和方法的名字分割開,有 4 種形式:
① 物件::例項方法
② 類::靜態方法
③ 類::例項方法
④ 類::new
注意:呼叫的方法的引數列表與返回值型別,都與函式式介面中的方法引數列表與返回值型別一致。
程式碼示例(使用到了函數語言程式設計的 4 個核心介面):
public class TestMethodRef {
public static void main(String[] args) {
// Lambda表示式簡化了匿名內部類,方法引用簡化了Lambda表示式
// 1.物件::方法名
Consumer<String> con = (s)->System.out.println(s); // lambda
con.accept("hello,world"); // hello,world
Consumer<String> con2 = System.out::println; // 方法引用
con2.accept("哈哈哈"); // 哈哈哈
// String也可以是自定義類
String s = new String("hello,world");
//Supplier<Integer> sup = ()->s.length(); // lambda
Supplier<Integer> sup = s::length; // 方法引用
System.out.println(sup.get()); // 11
// 2.類名::靜態方法(不常用)
//Comparator<Integer> com = (x,y)->Integer.compare(x,y); // lambda
Comparator<Integer> com = Integer::compare; // 方法引用
System.out.println( com.compare(1, 2) ); // -1: 1 < 2
TreeSet<Integer> ts = new TreeSet<Integer>(com);
System.out.println(ts); // ts就會遵循com指向的 Integer中的Compare方法進行排序
// 3.類名::例項方法名
//Function<String, Integer> fun = s->s.hashCode(); // lambda
Function<String, Integer> fun = String::hashCode; // 方法引用
Integer hash = fun.apply(s);
System.out.println(hash); // 2137655864
// 4.類::new 即 類名::構造方法
//Supplier<String> supp = ()->new String(); // lambda
Supplier<String> supp = String::new; // 方法引用
System.out.println(supp.get().getClass()); // class java.lang.String
}
}
4. 函式式介面 × 4
函數語言程式設計:函式的引數也是函式,函式返回的也是函式。
概念:如果一個介面只有 1 個公開抽象方法,則該介面為函式式介面。
- 為了確保介面達到只有1個方法的要求,介面名上新增註解 @FunctionalInterface
- Java8內建 4 個核心函式式介面interface。
位置:java.util.function
public class TestMethodInterface {
public static void main(String[] args) {
// 介面引用 指向 Lambda表示式的匿名內部類物件
Interface t = ()->System.out.println("函數語言程式設計...");
t.m(); // 函數語言程式設計...
}
}
@FunctionalInterface
interface Interface {
void m();
}
① Predicate 介面(斷言、返回真假)
根據賦值的Lambda表示式邏輯,用作一個引數的斷言(布林值函式)
成員方法:
boolean test(T t)
在給定的引數上執行這個斷言邏輯。
default Predicate<T> and(Predicate<? super T> other)
返回一個組合的斷言,表示該斷言與另一個斷言的短路邏輯AND。
static <T> Predicate<T> isEqual(Object targetRef)
返回根據 Objects.equals(Object, Object)測試兩個引數是否相等的 斷言 。
default Predicate<T> negate()
返回表示此斷言的邏輯否定的斷言。
default Predicate<T> or(Predicate<? super T> other)
返回一個組合的斷言,表示該斷言與另一個斷言的短路邏輯或。
基本使用:
Predicate<String> p1 = str -> str.length() == 9; // 字串長度是否等於9
Predicate<String> p2 = str -> str.startsWith("j"); // 是否以j開頭
Predicate<String> p3 = p1.and(p2); // 字串是否長度為9並且以j開頭
Predicate<String> p4 = p1.or(p2); // 字串是否長度為9或者以j開頭
Predicate<String> p5 = p1.negate(); // 字串長度是否不等於9
Predicate<String> p6 = Predicate.isEqual("Java"); // 字串是否等於Java
System.out.println(p1.test("aaa")); // false
System.out.println(p2.test("java")); // true
System.out.println(p3.test("jjjaaabbb"));// true
System.out.println(p4.test("ja"));// true
System.out.println(p5.test("123456789"));// false
System.out.println(p6.test("java"));// false
函式傳參:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class TestPredicate {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
list.add("zhangqi");
// Predicate斷言:過濾出來已zhang開頭的元素
List<String> ls = filter(list, (s)->s.startsWith("zhang"));
for (String string : ls) {
System.out.print(string + " "); // zhangsan zhangqi
}
}
public static List<String> filter(List<String> list, Predicate<String> p) {
List<String> l = new ArrayList<String>();
for (String s : list) {
if (p.test(s)) {
l.add(s);
}
}
return l;
}
}
② Consumer 介面(消費、有去無回)
根據賦值的Lambda表示式邏輯,接受單個輸入引數並且不返回結果的操作。
成員方法:
void accept(T t)
對給定的引數執行此操作。
default Consumer<T> andThen(Consumer<? super T> after)
返回一個組合的 Consumer ,按順序執行該操作,然後執行 after操作。
基本使用:
// 消費:給其內容,不關心其作何使用,沒有返回值
Consumer<String> c = s->System.out.println(s);;
c.accept("hello world!"); // hello world!
// andThen後執行
c.andThen(s->System.out.println("hello," + s)).accept("world"); // world hello,world
函式傳參:
import java.util.function.Consumer;
public class TestConsumer {
public static void main(String[] args) {
m1(100, (a)->System.out.println("今天掙錢了:" + a)); // 今天掙了100
m2(10, (a)->{
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}); // 0 1 2 3 4 5 6 7 8 9
}
public static void m1(double money, Consumer<Double> consumer) {
consumer.accept(money);
}
public static void m2(int num, Consumer<Integer> consumer) {
consumer.accept(num);
}
}
③ Supplier 介面(創造、無中生有)
根據賦值的Lambda表示式邏輯,根據只有1個抽象方法T get(),沒有引數,返回一個T型別的結果。
成員方法:
T get()
獲得結果。
基本使用:
Supplier<Double> sup = ()->new Double(Math.random());
System.out.println( sup.get() ); // 輸出1個隨機<1的小數
函式傳參:
import java.util.Random;
import java.util.function.Supplier;
public class TestSupplier {
public static void main(String[] args) {
int result = getSum(10, ()->new Random().nextInt(100));
System.out.println(result); // 10個100以內隨機整數的和
Supplier<Integer> sup = ()->{
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
};
System.out.println("1-100的和:" + sup.get()); // 5050
}
public static int getSum(int num, Supplier<Integer> supplier) {
int sum = 0;
for (int i = 0; i <= num; i++) {
sum += supplier.get();
}
return sum;
}
}
④ Function 介面(傳遞、返回資料)
根據賦值的Lambda表示式邏輯,計算T型別的值,返回R型別的值。
成員方法:
R apply(T t)
將此函式應用於給定的引數。
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
返回一個組合函式,首先將該函式應用於其輸入,然後將 after函式應用於結果。
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
返回一個組合函式,首先將 before函式應用於其輸入,然後將此函式應用於結果。
static <T> Function<T,T> identity()
返回一個總是返回其輸入引數的函式。
基本使用:
// String 為傳入 Lambda 表示式引數的型別T,Integer 為返回值的型別R
Function<String, Integer> up1 = (s)->s.length();
System.out.println( up1.apply("hello") ); // 5
// 將 up1 的 lambda 執行後,作為結果再執行 up2,組合在一起
Function<String, String> up2 = (s)->"aaa" + s;
System.out.println( up1.compose(up2).apply("12345") ); // 3+5==8
// 將 up2 的 lambda 執行後,作為結果然後再執行 apply
Function<String, String> up3 = (s)->"bbb" + s;
System.out.println( up3.andThen(up2).apply("11111") ); // aaabbb11111
// identity() 靜態方法,總是返回其輸入的引數
Function<String, String> up4 = Function.identity();
System.out.println( up4.apply("Jerry") );
函式傳參:
import java.util.function.Function;
public class TestFunction {
public static void main(String[] args) {
String up = stringUpper("hello,world", (s)->s.toUpperCase());
System.out.println(up); // HELLO,WORLD
}
public static String stringUpper(String s, Function<String, String> fun) {
return fun.apply(s);
}
}
5. Stream (流)介面 API
Stream 介面: 支援對一系列元素進行順序和並行的聚合操作功能介面,是Java8中處理陣列、集合的抽象概念。
- 可以執行非常複雜的查詢、過濾、對映等操作。
public interface Stream<T>
extends BaseStream<T,Stream<T>>
5.1 stream 基本操作
public class TestStream {
public static void main(String[] args) {
// Stream --> 陣列、集合
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu", "lucy");
// Stream 中儲存的是資料的操作,自身不儲存資料。
// 1.建立 Stream
Stream<String> stream = list.stream();
// 2.中間操作
Stream<String> center = stream.filter((s)->s.length()>=5);
// 3.最終操作
System.out.println("名字長度>=5的是:");
center.forEach(System.out::println);
// 一行套娃版:
System.out.println();
list.stream().filter(s->s.length()>=5).forEach(System.out::println);
}
}
// zhangsan wangwu zhaoliu
5.2 stream 中間操作
常用API: filter limit distinct map sorted
Stream<T> filter(Predicate<? super T> predicate)
返回由與此給定謂詞匹配的此流的元素組成的流。
Stream<T> limit(long maxSize)
返回由此流的元素組成的流,截短長度不能超過 maxSize 。
Stream<T> distinct()
返回由該流的不同元素(根據 Object.equals(Object) )組成的流。
<R> Stream<R> map(Function<? super T,? extends R> mapper)
返回由給定函式應用於此流的元素的結果組成的流。
Stream<T> sorted()
返回由此流的元素組成的流,根據自然順序排序。
Stream<T> sorted(Comparator<? super T> comparator)
返回由該流的元素組成的流,根據提供的 Comparator進行排序。
中間操作示例:
public class TestStreamAPI {
public static void main(String[] args) {
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu", "zuee", "zhangsan");
// filter:過濾,指定規則
System.out.println("--------------filter---------------");
list.stream().filter(s->s.startsWith("z")).filter(s->s.contains("an")).forEach(System.out::println); // zhangsan ×2
// limit:截斷,返回不超過指定數量
System.out.println("--------------limit---------------");
list.stream().limit(2).forEach(System.out::println); // zhangsan lisi
// distinct:篩選,利用 hashCode 和 equals,不會影響原資料
System.out.println("--------------distinct---------------");
List<String> ls = new ArrayList<String>();
list.stream().distinct().forEach(s->ls.add(s));
ls.stream().forEach(System.out::println); // 過濾掉了重複的1個 zhangsan
// map:給到T返回R,自動推斷型別。不是集合!不是集合!不是集合!
System.out.println("--------------map---------------");
list.stream().map(s->s.toUpperCase()).forEach(System.out::println); // 全轉大寫
list.stream().map(String::toUpperCase).forEach(System.out::println); // 全轉大寫(方法引用)
// sorted:自然排序,預設升序(基本型別直接排序,引用型別需要實現 Comparable 介面中的 compareTo)
System.out.println("--------------sorted---------------");
list.stream().sorted().forEach(System.out::println);
System.out.println("--------------sorted()---------------");
// sorted(Comparator<? super T> comparator):定製排序
list.stream().sorted((x,y)->x.charAt(0) - y.charAt(0)).forEach(System.out::println); // 實現 Comparable 介面的匿名內部類
}
}
5.3 stream 終止操作
常用API: count forEach anyMatch allMatch noneMatch findFirst findAny min max
long count()
返回流中的元素個數。
void forEach(Consumer<? super T> action)
對此流的每個元素執行遍歷操作。
boolean anyMatch(Predicate<? super T> predicate)
或,流中是否有包含指定規則的元素
boolean allMatch(Predicate<? super T> predicate)
且,流中是否全部包含指定規則的元素
boolean noneMatch(Predicate<? super T> predicate)
非,流中是否都不包含指定規則的元素
Optional<T> findFirst()
返回流的第一個元素的Optional,如果流為空,則返回一個空的Optional 。
Optional<T> findAny()
返回流的任意一個隨機元素的Optional,如果流為空,則返回一個空的Optional 。
Optional<T> max(Comparator<? super T> comparator)
根據提供的 Comparator 返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator)
根據提供的 Comparator 返回此流的最小元素。
終止操作示例:
public class TestStreamEnd {
public static void main(String[] args) {
List<String> list = Arrays.asList("changsan", "lisi", "wangwu", "zhaoliu", "zuee");
// 1.forEach: 遍歷
list.stream().forEach(System.out::println); // changsan lisi wangwu zhaoliu zuee
// 2.count: 流中元素的個數
long count = list.stream().filter(s->s.length()>4).count();
System.out.println("流中長度>4元素個數:" + count); // 3
// 3.anymatch: 或,是否有包含的元素
boolean bool1 = list.stream().filter(s->s.length()>4).anyMatch(s->s.startsWith("w"));
System.out.println("流中是否是有包含 w 開頭的元素:" + bool1); // true
// 4.allmatch: 且,是否全部都包含的元素
boolean bool2 = list.stream().filter(s->s.length()>4).allMatch(s->s.startsWith("w"));
System.out.println("流中是否全是包含 w 開頭的元素:" + bool2); // false
// 5.noneMatch: 非,是否沒有匹配的元素
boolean bool3 = list.stream().filter(s->s.length()>4).noneMatch(s->s.startsWith("a"));
System.out.println("流中是否沒有包含 a 開頭的元素:" + bool3); // true
// 6.findFirst: 返回流中第一個元素
String s1 = list.stream().filter(s->s.length()>4).findFirst().get();
System.out.println("流中的第一個元素是:" + s1); // changsan
// 7.findAny: 返回流中任意一個元素
String s2 = list.stream().findAny().get();
String s3 = list.parallelStream().findAny().get(); // 並行流
System.out.println("流中的隨機1個元素是:" + s2 + " " + s3); // changsan wangwu
// 8.max/min: 返回流中的一個最大/最小的元素,需要在max/min中指定 Comparable 介面的比較規則
String max = list.stream().max((e1, e2)->e1.charAt(0)-e2.charAt(0)).get();
System.out.println("首字母最大的是:" + max); // zhaoliu
}
}
序列與並行的 Stream 效率對比:
public class TestStreamOther {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 1000000; i++) {
list.add(UUID.randomUUID().toString());
}
// stream序列:一條執行路徑,單執行緒
System.out.println("序列執行時間:");
long start = System.currentTimeMillis();
long count = list.stream().sorted().count();
System.out.println("排序的元素數量:" + count);
System.out.println("用時:" + (System.currentTimeMillis() - start)); // ≈1050毫秒
// parallelStream 並行:多條執行路徑,多執行緒
System.out.println("並行執行時間:");
start = System.currentTimeMillis();
count = list.parallelStream().sorted().count();
System.out.println("排序的元素數量:" + count);
System.out.println("用時:" + (System.currentTimeMillis() - start)); // ≈520毫秒
}
}
相關文章
- JDK1.8新特性總結JDK
- JAVA8新特性用法Java
- Java 新特性總結——簡單實用Java
- Java8常用的新特性總結Java
- JDK1.8新特性值OptionalJDK
- JDK1.8新特性--Lambda表示式JDK
- jdk1.8新特性:Lambda表示式JDK
- Promise特性及用法Promise
- html5新特性總結HTML
- ES6新特性總結
- React 16 新特性使用總結React
- css3新特性總結CSSS3
- java中的HashMap用法總結JavaHashMap
- JDK1.8新特性之Lambda表示式JDK
- JDK1.8新特性之Lambda表示式()->JDK
- PHP 各個版本新特性總結PHP
- JDK1.8的新特性之Lambda表示式JDK
- [Java學習筆記]JDK1.8新特性學習(一)Lambda表示式Java筆記JDK
- Java日期時間操作基礎——包含JDK1.8時間操作新特性JavaJDK
- iOS 12正式版新特性總結iOS
- JDK8新特性學習總結JDK
- jdk1.8 新特性之 如何寫lambda表示式JDK
- JDK 1.5 - 1.8 各版本的新特性總結JDK
- react-router v6新特性總結React
- Java基礎 | Stream流原理與用法總結Java
- Promise用法總結Promise
- layui用法總結UI
- axios用法總結iOS
- less用法總結
- pandas用法總結
- Const 用法總結
- Oracle特性總結Oracle
- 總結:JDK1.5-JDK1.8各個新特性JDK
- Java 11新特性Java
- Java 8 新特性Java
- Java 8 新特性Java
- Java 17新特性Java
- HTML中Progress標籤的定義及用法總結!HTML