Java8 新特性--Lambda&函數式接口&雙冒號引用&Stream


前言

哈希表在Java中應用非常多
1.8以前,HashMap爲數組-鏈表的形式,但是發送碰撞的概率依舊不低,碰撞意味着低效率;
1.8之後,HashMap改爲數組-鏈表-紅黑樹的形式。
當滿足某些條件(比如鏈表的節點個數大於8且數組的長度大於64時),就將滿足條件的鏈表(節點個數大於8的)轉爲紅黑樹,提高了查詢的效率

1. Lambda

Lambada 簡介:
Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性。

Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。使用 Lambda 表達式可以使代碼變的更加簡潔緊湊

記住:函數作爲參數傳遞進方法中
兩個東西:函數參數、方法

示例:

匿名類寫法
new Thread(new Runnable(){
	@Override
	public void run(){
	System.out.println("hello");
	}	
}).start();

Lambada寫法
new Thread(()->System.out.println("hello")).start();

上述例子:
方法:Thread().start();
函數參數:()->System.out.println(“hello”)
這個函數參數實際上是Runnable中的run函數

編譯器會將 “System.out.println(“hello”)” 編譯成Runnable.run 的執行指令。
可代碼中我們並沒有指明Run方法,這是因爲 run 方法是Runnable接口的唯一方法,也就是說如果Runable有多個方法是不能使用Lambada表達示的,這種支持Lambada的接口統稱函數式接口。

函數參數的寫法:

() -> {}

    ():接口方法的括號,接口方法如果有參數,也需要寫參數。若只有一個參數時,括號可以省略。
    -> : 分割左右部分。
    {} : 要實現的方法體。只有一行代碼時,可以不加括號,可以不寫return。

2. 函數式接口

必須是 函數式接口 纔可以使用lambada 表達示 ,函數式接口籠統的講就是隻有一個抽像方法接口就是函數式接口,其詳細特徵如下:

  • 接口中只有一個抽像方法 會被編譯器自動認識成函數式接口
  • 有多個方法,但是Object類提供的方法、static和default方法除外

Java8內置的四大核心函數式接口

package concurrency.chapter10;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * Consumer<T> 消費型接口
 *      void accept(T t);
 *      Consumer<T> andThen(Consumer<? super T> after)
 *
 * Supplier<T> 供給型接口
 *      T get();
 *
 * Predicate<T> 斷言型接口
 *      boolean test(T t);
 *      default Predicate<T> and(Predicate<? super T> other)
 *      default Predicate<T> negate()
 *      default Predicate<T> or(Predicate<? super T> other)
 *      static <T> Predicate<T> isEqual(Object targetRef)
 *
 * Function<T,R> 函數型接口
 *      R apply(T t);
 *      default <V> Function<V, R> compose(Function<? super V, ? extends T> before)
 *      default <V> Function<T, V> andThen(Function<? super R, ? extends V> after)
 *      static <T> Function<T, T> identity() {
 *         return t -> t;
 *     }
 *
 */
public class test {

    static class Money{
        // 是否是真錢
        final boolean really;
        // 錢的數量
        final double num;
        Money(double num, boolean really){
            this.really=really;
            this.num=num;
        }

        public boolean isReally() {
            return really;
        }

        public double getNum() {
            return num;
        }
    }

    public static void main(String[] args) {
        // 創建錢
        final Money money = new Money(100, true);

        // 供給--產生對象
        System.out.println("小明掏出"+supply(money::getNum)+"元,交給了老闆");

        // 消費--使用對象
        consumed(money,(m)->{
            System.out.println("老闆收到了"+m.getNum()+"元");
        });

        //斷言型--判斷操作
        boolean flag = pridicated(money, Money::isReally);
        System.out.println("老闆查看錢,發現是"+ (flag?"真":"假") +"錢");

        //函數型--處理對象
        System.out.println(func(flag,m-> m?"老闆把硬盤遞給了小明":"老闆沒收了小明的假幣,並報了警"));
    }

    // 消費
    public static void consumed(Money money, Consumer<Money> consumer){
        consumer.accept(money);
    }

    // 供給
    public static double supply(Supplier<Double> supplier){
        return supplier.get();
    }

    // 斷言
    public static boolean pridicated (Money money, Predicate<Money> predicate){
        return predicate.test(money);
    }

    // 函數型
    public static String func(boolean flag,Function<Boolean,String> function){
        return function.apply(flag);
    }
}

3. 方法引用與構造器引用

==注意!==這些引用方法的參數列表都需要與函數式接口中的抽象方法參數列表保持一致;
比如說構造器引用,具體引用的哪個構造器,取決於你選擇的函數式接口的抽象方法的參數列表

方法引用

package concurrency.chapter10;

import java.util.Arrays;
import java.util.function.*;

/**
 * 方法引用:如哦lambda體中已有實現,則可以使用方法引用
 * 語法格式:
 *      對象::實例方法名
 *      類::靜態方法名
 *      類::實例方法名
 */
public class test2 {

    static class User{
        String name;
        User(String name){
            this.name=name;
        }
        public String getName(){return this.name;};
    }
    public static void main(String[] args) {
        // 類::靜態方法
        Consumer<String> consumer = System.out::println;
        consumer.accept("111");

        // 對象::實例方法
        User user = new User("testUser");
        Supplier<String> supplier = user::getName;
        consumer.accept(supplier.get());

        // 類::實例方法
        /**
         * 這種情況比較特殊,當且僅當
         *      lambda中有兩個參數,第一個時實例方法的調用者,第二個是實例方法的參數,
         *      這種情況下,可以使用類::實例方法名
         */
        BiPredicate<String,String> predicate1 = (x,y)->x.equals(y);
        BiPredicate<String,String> predicate2 = String::equals;
    }
}

構造器引用
ClassName::new
選擇的哪個構造器,將與抽象方法的參數進行匹配

數組引用
Type[]::new

Function<Integer,User[]> function = User[]::new;
User[] users = function.apply(5);

未完待續

4. Stream

5. 接口中的默認方法與靜態方法

6. 新時間日期API

7. 其他新特性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章