JAVA  lambda 表達式

目錄

JAVA  lambda 表達式 1

概要 1

一. 函數式接口的概念 1

二. 例子 2

2.1自定義一個只有一個方法的接口如下 2

2.2接口的實現調用 2

三. ForEach 3

四:Lambda方法的傳遞 5

 

JAVA  lambda 表達式

概要

Java8已經出來好幾年了,現在依然有很多人在用java7,在技術方面固步自封自然不是好事,接受新的事物,與時俱進纔不會被淘汰。面向對象編程,這麼多年一直很火熱,但是受制於語法的複雜,在近年來出現了一些優秀的函數是編程,在函數是編程的概念裏,方法也是甚至可以當作參數傳遞。Java8的lambda表達式其實就是想函數編程靠近的一種新的編程方式,它的語法簡單,減少了代碼的冗餘,相較與以往的內部類寫起來更簡單,下面我們來一起看看lambda的使用方式。

學習Lambda表達式必須得瞭解的概念:函數式接口。

在函數式編程語言中,Lambda表達式的類型是函數。

而在Java中,Lambda表達式是對象,它們必須依附於一類特別的對象類型——函數式接口(Functional Interface)。

接下來我們看下函數式接口的定義:

  1. 如果一個接口中,有且只有一個抽象的方法(Object類中的方法不包括在內),
  2. 那這個接口就可以被看做是函數式接口,它被@FunctionalInterface修飾。

 

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

上面是Runnable接口的聲明,在Java8後,Runnable接口多了一個FunctionalInterface註解,表示該接口是一個函數式接口。但是如果我們不添加FunctionalInterface註解的話,如果接口中有且只有一個抽象方法時,編譯器也會把該接口當做函數式接口看待。

 

 

 

2.1自定義一個只有一個方法的接口如下

public interface MyLambda<T> {
    public T getData(T t);
}

2.2接口的實現調用

  1. 以前的實現方式,是直接用匿名內部類的方式


public class Main {
    public static void main(String[] args) {
        MyLambda<String> myLambda=new MyLambda<String>() {
            @Override
            public String getData(String s) {
                return s+" test";
            }
        };
        System.out.println(myLambda.getData( "hello" ));
    }
}

  1. 替換成 Lambda

public class Main {
    public static void main(String[] args) {
        MyLambda<String> myLambda= s -> s+" test";
        System.out.println(myLambda.getData( "hello" ));
    }
}

由此可見,你可以簡單將lambda表達式看成匿名內部類的簡寫形式。我們來分析一下,仔細看上面兩部分的代碼,對比一下,第一部分的getData(String S),和第二部分的 s ->其實s ->

就是對getData(String S)的實現,既然如此那麼我們當然可以把Lambda部分直接寫成 (String  s)-> s+" test";或者是(s) -> s+" test";這個時候相比你以及該看出來了,->左側是方法的參數,右側是方法的實現。之所以左側可以省略類型,是因爲接口中只有一個方法,java內部推斷機制,可以直接推斷出類型,因此在實現的時候根本不需要指定類型。一般lambda有以下幾種類型。

  1. ()-> 66接口中的方法不需要參數,並且該方法的返回值爲 66
  2. (x)->x+test 該方法接受一個參數x,最後返回了一個x+test的返回值
  3. ()-> {

    總結:->右側是對方法的實現,因此這部分是方法體的代碼,當方法體只有一句話的時候大括號可以省略,當多行的時候你需要加上大括號。

}

熟悉scala的同學,肯定對forEach不陌生。它可以迭代集合中所有的對象,java8中也提供了forEach()迭代功能。下面是java的集合類遍歷集合的操作,在這裏我們來探討一下ForEach()。

List<String> list = new ArrayList<>(  );
list.add( "北京" );
list.add( "歡迎" );
list.add( "你" );
list.forEach( s -> System.out.println(s) );

看到這裏相比你就明白了,forEach裏面其實就是Lambda表達式,我們打開源碼看。

public interface Iterable<T> {
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();

    /**
     * Performs the given action for each element of the {@code Iterable}
     * until all elements have been processed or the action throws an
     * exception.  Unless otherwise specified by the implementing class,
     * actions are performed in the order of iteration (if an iteration order
     * is specified).  Exceptions thrown by the action are relayed to the
     * caller.
     *
     * @implSpec
     * <p>The default implementation behaves as if:
     * <pre>{@code
     *     for (T t : this)
     *         action.accept(t);
     * }</pre>
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */


    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

 

 

}

看見沒,forEach方法裏面的參數是一個Consumer<T> action接口,接着在for循環裏遍歷了Iterator<T>然後將遍歷出的每一個元素傳遞到了action裏面的accept()方法中,下面打開Consumer<T>

 

//Consumer明顯就是一個函數是接口

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

四:Lambda方法的傳遞

前面說過,函數是編程語言,方法可以當作參數傳遞,javaLambda雖然沒能完全的實現這樣的邏輯,但是也有了基本的應用,下面介紹一下Lambda  “::”進行方法的傳遞。

  1. 首先我們自定義一個符合Lambda的函數式接口

@FunctionalInterface
public interface MyLambda<T> {
    public T accept(T t);
}

該接口有一個自定義的方法,這個方法返回一個T類型的數據。這個接口中的方法必須要被實現纔可以用,這個大家都知道的。其實並不需要你每一次都再用的時候去實現,你可以去別的方法裏面直接拿一個和accept方法特性一樣(特性一樣的意思是,你不能將沒有返回值的方法傳遞給有返回值的接口,飯之亦然)的方法直接將其當作accept來用,這就相當於將別的類的方法傳遞給了MyLambda<T>這個接口。話不多說,下面我們自定義一個Test類。

  1. class Test {
        // static methods
        static String startsWith(String s) {
            return s;
        }
       public String  endWith(String s) {
            return s;
        }
    }

 

 

  1. 實現普通方法傳遞:

public class Main {
    public static void main(String[] args) {
        Test test = new Test();

//將test類中的方法當成accept方法的實現體,myLambda.accept()實際上調用的就是test中的//endwith方法
        MyLambda<String> myLambda = test::endWith;
        System.out.println( myLambda.accept( "lambda lambda lambda lambda" ) );
    }
}

  1. 實現靜態方法的傳遞

 

public class Main {
    public static void main(String[] args) {
        MyLambda<String> myLambda = Test::startsWith;
        System.out.println( myLambda.accept( "lambda lambda lambda lambda" ) );
    }
}

 

 

 

 

 

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