Java基礎(五):JDK1.8新特性
JDK1.8新特性
lambda表示式
Lambda
lambda作用:lambda是一個語法糖,簡化匿名內部類的使用。
lambda使用條件
- 引數或者變數必須是介面
- 介面中只包含一個抽象方法
lambda格式
(引數型別 引數名稱 …)-> { 程式碼語句;}
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("run");
}
});
//------------Lambda標準格式分割線-----------------
new Thread (() -> {
System.out.println("run");
});
lambda省略規則
- 引數型別可以省略。
- 只有一個引數時,()可以省略。
- 只有一條語句時,‘return’ , ‘{}’, '; ’ 都可以省略,但必須一起省略。
函式式介面
自定義函式式介面
使用@FunctionalInterface可以檢查介面是否只有一個抽象方法,不是則報錯。
@FuntionalInterface
public interface MyFunction {
void work();
}
JAVA自帶的函式式介面
-
Supplier介面
供給型介面,無引數有返回值
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
-
Consumer介面
消費型介面,有引數無返回值
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
-
Function介面
方法介面,有引數也有返回值
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
-
Perdicate介面
預測介面,有引數返回布林值。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
方法引用
作用
簡化lambda表示式的使用。
條件
- Lambda表示式中只有一條語句。
- 語句中除了傳入的引數不能有額外的引數。
引用方式
1. 類名::靜態方法名
public static void main(String[] args) {
test01(System.out::println, 20);
}
private static void test01(Consumer<Integer> consumer, Integer in){
consumer.accept(in);
}
2. 物件名::成員方法名
注意
- 呼叫方法中的引數必須和介面中方法的引數型別一模一樣。
- 介面抽象方法有返回值,呼叫方法也要有返回值。
public static void main(String[] args) {
String str = "helloword";
//lambda格式
test02(() -> {
return str.toUpperCase();
});
//方法引用格式
test02(str::toUpperCase);
}
private static void test02(Supplier<String> supplier) {
String s = supplier.get();
System.out.println(s);
}
####3. 類名::new
引用構造方法
public static void main(String[] args) {
String str = "helloword";
test03(Person::new);
}
private static void test03(Function<String, Person> function) {
Person hello = function.apply("hello");
System.out.println(hello);
}
Person類
class Person{
private String name;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
####4. 陣列::new
引用陣列構造器
public static void main(String[] args) {
String str = "helloword";
//lambda格式
test04((Integer i) ->{
return new int[i];
});
//方法引用格式
test04(int[]::new);
}
private static void test04(Function<Integer,int[]> function) {
int[] apply = function.apply(10);
System.out.println(apply.length);
}
Stream
“Stream流”其實是一個集合元素的函式模型,它並不是集合,也不是資料結構,其本身並不儲存任何元素(或其地址值)。
當需要對多個元素進行操作(特別是多步操作)的時候,考慮到效能及便利性,我們應該首先拼好一個“模型”步驟方案,然後再按照方案去執行它。而方案就是一種“函式模型”。圖中的每一個方框都是一個“流”,呼叫指定的方法,可以從一個流模型轉換為另一個流模型。而最右側的數字3是最終結果。
這裡的 filter 、 map 、 skip 都是在對函式模型進行操作,集合元素並沒有真正被處理。只有當終結方法 count或者foreach執行的時候,整個模型才會按照指定策略執行操作。而這得益於Lambda的延遲執行特性。
Stream作用
可完美展示無關邏輯方式的語義,解決集合語法冗餘的弊端。
獲取流物件
-
使用Collection中的預設方法
default Stream<E> stream()
-
使用Stream中的靜態方法
public static<T> Stream<T> of(T... values)
常用方法
-
Stream返回值有Stream流和非Stream流兩種
-
每個Stream流只能用一次
-
返回Stream流可以進行函式拼接呼叫,返回非Stream流則呼叫結束。
過濾方法
Stream<T> filter(Predicate<? super T> predicate)
對映方法
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
限制集合的個數
Stream<T> limit(long maxSize)
從零開始跳過n個元素返回的流
Stream<T> skip(long n)
拼接兩個流
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
統計流的個數
long count()
遍歷流
void forEach(Consumer<? super T> action)
Demo
/*
1. 第一個隊伍只要名字為3個字的成員姓名;
2. 第一個隊伍篩選之後只要前3個人;
3. 第二個隊伍只要姓張的成員姓名;
4. 第二個隊伍篩選之後不要前2個人;
5. 將兩個隊伍合併為一個隊伍;
6. 根據姓名建立 Person 物件;
7. 列印整個隊伍的Person物件資訊。
*/
public class StreamDemo {
public static void main(String[] args) {
Stream<String> stream01 =
Stream.of("迪麗熱巴", "宋遠橋", "蘇星河", "老子", "莊子", "孫子", "洪七公");
Stream<String> stream02 =
Stream.of("古力娜扎", "張無忌", "張三丰", "趙麗穎", "張二狗", "張天愛", "張三");
//第一個隊伍操作
Stream s1 = stream01.filter(s -> s.length() == 3).limit(3);
//第二個隊伍操作
Stream s2 = stream02.filter(s -> s.startsWith("張")).skip(2);
//合併
Stream<String> res = Stream.concat(s1, s2);
//建立物件並列印
res.map(Person::new).forEach(System.out::println);
}
}
結果:(Person類在前文有)
Person{name='宋遠橋'}
Person{name='蘇星河'}
Person{name='洪七公'}
Person{name='張二狗'}
Person{name='張天愛'}
Person{name='張三'}
Stream物件轉換為集合
<R, A> R collect(Collector<? super T, A, R> collector)
Stream<String> stream =
Stream.of("迪麗熱巴", "宋遠橋", "蘇星河", "老子", "莊子", "孫子", "洪七公");
//轉成List
List<String> list = stream.collect(Collectors.toList());
//轉為Set
Set<String> set = stream.collect(Collectors.toSet());
Stream物件轉換為陣列
<A> A[] toArray(IntFunction<A[]> generator)
Stream<String> stream =
Stream.of("迪麗熱巴", "宋遠橋", "蘇星河", "老子", "莊子", "孫子", "洪七公");
String[] arr = stream.toArray(String::new);
併發Stream流
- 使用Collection類的
default Stream<E> parallelStream()
獲取併發流物件。 - 使用Stream類的
S parallel()
獲取併發流物件。