1. 程式人生 > >java8-Lambda表示式介紹

java8-Lambda表示式介紹

簡介

 Lambda,“語法糖”,是一個匿名函式,我們可以把Lambda表示式理解為是一個可以傳遞的程式碼(將程式碼像資料一樣進行傳遞)。可以寫出更簡潔、更靈活的程式碼。作為一種更緊湊的程式碼風格,使java的語言表達能力得到了提升。

為什麼使用Lambda表示式

 可以以下程式碼

@Test
    public void test4(){
    	//使用匿名內部類
        Comparator<Integer> comparator = new Comparator<>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        System.out.println(comparator.compare(2,3));
        System.out.println("----------------------------------------");
        //使用Lambda表示式
        Comparator<Integer> handler = (x, y) -> Integer.compare(x, y);
        System.out.println( handler.compare(2,3));
    }

輸出

-1
----------------------------------------
-1

從以上程式碼可以看出不使用Lambda表示式時,程式碼非常的繁瑣,隨著回撥模式和函數語言程式設計風格的日益流行,我們需要在Java中提供一種儘可能輕量級的將程式碼封裝為資料的方法。匿名內部類並不是一個好的選擇,因為:  1. 語法過於冗餘  2. 匿名內部類中this和變數名容易使人產生誤解  3. 型別載入和例項建立語義不夠靈活 java8解決了這些問題 因此你可以使用更少的程式碼來實現同樣的功能。

Lambda表示式的基礎語法

概念

 在Java8中引入了一個新的操作符“->” 稱作箭頭操作符或Lambda表示式。 Lambda分為兩個部分

  • 左側:Lambda表示式的引數列表
  • 右側:Lambda表示式中所需執行的功能,即Lambda體

語法格式

  1. 無引數嗎,無返回值
()->System.out.println("hello world!");
  1. 有引數,並且無返回值
(x)->System.out.println(x);
  1. 若只有一個引數,則小括號可以省略不寫
x->System.out.println(x);
  1. 有兩個以上的引數,有返回值,並且Lambda體中有多條語句時
Comparator<Integer> con = (x,y)->{
		System.out.println("函式式介面");
		return Integer.compare(x,y);
}
  1. 若Lambda表示式中只有一條語句時
Comparator<Integer> com =(x,y)->Integer.compare(x,y);
  1. Lambda 表示式的引數列表的引數型別可以省略不寫,因為JVM編譯器通過上下文推斷出資料型別,即型別推斷
Comparator<Integer> com=(Integer x,Integer y)->Integer.compare(x,y);
Comparator<Integer> com=(x,y)->Integer.compare(x,y);

注意

Lambda表示式需要“函式式介面”的支援 函式式介面:介面中只有一個抽象方法的介面稱為函式式介面,可以使用註解@FunctionalInterface來修飾,可以檢查是否是函式式介面

Java8內建的四大核心函式式介面

介紹

函式式介面 說明 引數型別 返回型別 內建方法 用途
Consumer 消費型介面 T void void accept(T t) 對型別T引數操作,無返回結果。
Supplier 供給型介面 T T get() 返回T型別引數。
Function 函式型介面 T R R apply(T t) 對於型別T引數操作,返回R型別引數。
Predicate 斷言型介面 T boolean boolean test(T t) 對型別T進行條件篩選操作,返回boolean.
  1. Consumer 消費型介面
    /**
     * Consumer<T> 消費者型別介面 無返回值
     */
    @Test
    public void consumer(){
        consumers("張三", new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s+"去了北京天安門");
            }
        });
        System.out.println("--------Lambda表示式--------");
        consumers("李四",n-> System.out.println(n+"去了九寨溝"));
    }

    void consumers(String Name,Consumer<String> con){
        con.accept(Name);
    }
    ------------------輸出------------------
    張三去了北京天安門
	--------Lambda表示式--------
	李四去了九寨溝
  1. Supplier 供給型介面
    /**
     * Supplier 供給型介面 T get();
     */
    @Test
    public void supplier(){
        List<Integer> list1 = getNumList(5, new Supplier<Integer>() {
            @Override
            public Integer get() {
                return (int) (Math.random() * 10);
            }
        });
        list1.forEach(System.out::println);
        System.out.println("--------Lambda表示式--------");
        List<Integer> list = getNumList(5,()->(int)(Math.random()*100));
        list.forEach(System.out::println);
    }

    List<Integer> getNumList(int num , Supplier<Integer> sup){
        List<Integer> list = new ArrayList<>();
        for (int i=0; i<num; i++){
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }
    -----------------輸出------------------
    3
	3
	0
	1
	8
	--------Lambda表示式--------
	21
	5
	92
	69
	69
    
  1. Function 函式型介面
    /**
     * Function<T,R>  函式型介面 R apply(T t);
     */
    @Test
    public void function(){
        String s = handle("hjkwegfkGHJKjksagdhfjklgwhejf", new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s.toUpperCase();
            }
        });
        System.out.println(s);
        System.out.println("--------Lambda表示式--------");
        String s2 = handle("hdjagshjgquga", s1 -> s1.toUpperCase());
        System.out.println(s2);
    }

    String handle(String str, Function<String,String> f){
        return f.apply(str);
    }
    --------------輸出--------------------
    HJKWEGFKGHJKJKSAGDHFJKLGWHEJF
	--------Lambda表示式--------
	HDJAGSHJGQUGA
  1. Predicate 斷言型介面
    /**
     * Predicate 斷言型介面 boolean test(T t)
     */
    @Test
    public void predicate(){
        List<Integer> list = Arrays.asList(10, 9, 20, 31, 21, 42);
        //如果數大於18就加入新的集合中
        List<Integer> filter = filter(list, new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer > 18;
            }
        });
        filter.forEach(System.out::println);
        System.out.println("--------Lambda表示式--------");
        List<Integer> f = filter(list, x -> x > 18);
        f.forEach(System.out::println);
    }

    List<Integer> filter(List<Integer> list, Predicate<Integer> p){
        List<Integer> list1 = new ArrayList<>();
        for (Integer integer : list) {
            if(p.test(integer)){
               list1.add(integer);
            }
        }
        return list1;
    }
    -----------------------輸出-----------------
    20
	31
	21
	42
	--------Lambda表示式--------
	20
	31
	21
	42

其他延申函式式介面

函式式介面 引數型別 返回型別 內建方法 用途
BiFunction T,U R R apply(T t,U u) 對型別T,U引數進行操作,返回R型別結果
UnaryOperator T T T apply(T t) 對型別T物件進行一元運算,並返回T型別的結果
BinaryOperator T,T T T apply(T t1,T t2) 對型別T物件進行二元運算,並返回T型別的結果
BiConsumer T,U void void accept(T t,U u) 對型別T,U引數進行操作
ToIntFunction /ToLongFunction / ToDoubleFuction T int,long,double int applyAsInt(T value)/ long applyAsLong(T value) /double applyAsDouble(T value) 分別計算int,long,double值
IntFunction /LongFunction / DoubleFuction int,long,double R R apply(int value)/R apply(longvalue) /R apply(double value) 引數分別是int,long,double型別函式

方法引用

 若Lambda體中的功能已經有方法提供了實現,可以使用方法引用(可以將方法引用理解為Lambda表示式的另外一種表現形式)

基本的引用

  1. 物件::例項方法
User u =new User();
u::getName
  1. 類名::靜態方法名
Comparator<Integer> handler = Integer::compare;
  1. 類名::例項方法名
User::getName

注意

  1. 方法引用所引用的方法的引數列表與返回值型別,需要與函式式介面中的抽象方法的引數列表和返回值保持一致
  2. 若Lambda的引數列表的第一引數,是例項方法的呼叫者,第二個引數(或無參)是例項方法的引數時,格式為ClassName::MethodName

擴充套件

  1. 構造器引用 構造器的引數列表需要與函式式介面中的引數列表保持一致 類名::new
User::new 
  1. 陣列引用 型別[]::new
Integer[]::new