1. 程式人生 > >Java基礎(五):JDK1.8新特性

Java基礎(五):JDK1.8新特性

JDK1.8新特性

lambda表示式

Lambda

lambda作用:lambda是一個語法糖,簡化匿名內部類的使用。

lambda使用條件

  1. 引數或者變數必須是介面
  2. 介面中只包含一個抽象方法

lambda格式

(引數型別 引數名稱 …)-> { 程式碼語句;}

new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("run");
    }
});

//------------Lambda標準格式分割線-----------------
new Thread
(() -> { System.out.println("run"); });

lambda省略規則

  1. 引數型別可以省略。
  2. 只有一個引數時,()可以省略。
  3. 只有一條語句時,‘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表示式的使用。

條件

  1. Lambda表示式中只有一條語句。
  2. 語句中除了傳入的引數不能有額外的引數。

引用方式

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流”其實是一個集合元素的函式模型,它並不是集合,也不是資料結構,其本身並不儲存任何元素(或其地址值)。

1541382881644

​ 當需要對多個元素進行操作(特別是多步操作)的時候,考慮到效能及便利性,我們應該首先拼好一個“模型”步驟方案,然後再按照方案去執行它。而方案就是一種“函式模型”。圖中的每一個方框都是一個“流”,呼叫指定的方法,可以從一個流模型轉換為另一個流模型。而最右側的數字3是最終結果。

​ 這裡的 filter 、 map 、 skip 都是在對函式模型進行操作,集合元素並沒有真正被處理。只有當終結方法 count或者foreach執行的時候,整個模型才會按照指定策略執行操作。而這得益於Lambda的延遲執行特性。

Stream作用

可完美展示無關邏輯方式的語義,解決集合語法冗餘的弊端。

獲取流物件

  1. 使用Collection中的預設方法default Stream<E> stream()

  2. 使用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流

  1. 使用Collection類的default Stream<E> parallelStream()獲取併發流物件。
  2. 使用Stream類的S parallel()獲取併發流物件。