java8新特性(二)_lambda表達式


最近一直找java8相關新特性的文章,發現都太沒有一個連貫性,畢竟大家寫博客肯定都有自己的側重點,這里找到一本書,專門介紹java8新特性的,感覺大家可以看看《寫給大忙人看的JavaSE8》.這里我會結合書中的知識以及網上的知識,對於java8 的新特性進行總結,當然我自己寫的也會有自己的側重點。

java8為什么增加了函數式編程

java作為一門面向對象的編程語言誕生於20世紀90年代。在當時,面向對象編程是軟件開發的主流模式。

由於最近在並發和事件驅動(或者稱為“互動”)編程中的優勢,函數式編程又逐漸變得重要起來。

這並不意味着面向對象編程不好,相反,最終的趨勢是將面向對象編程和函數編程結合起來。

java8主要在原來面向對象的基礎上增加了函數式編程的能力.

函數式編程的語言我就了解過一個_Erlang,有興趣的大家可以看看Erlang這門語言。比如消息中間件rabbitmq 就是采用erlang寫的。只要用過erlang的一定知道堅強2002和阿里的余鋒。還有再推薦一個博客為“沒有開花的樹”的博主。至少對我幫助蠻多的。(有點扯遠了)

為什么要使用lambda表達式

lambda表達式的定義

lambda表達式是一段可以傳遞的代碼,因此它可以被執行一次或者多次。

實戰代碼對比

之前我們要在另一個獨立線程中執行一些邏輯時,通常會將代碼放到一個實現Runnable接口的類的run方法中。如下面

public class Worker implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("doWork" + i);
        }
    }
}


執行代碼

    public static void main(String[] args) {
        Worker worker = new Worker();
        new Thread(worker).start();

    }

這段代碼的關鍵在於,run方法中包含了你希望在另一個線程中需要執行的代碼。

到現在為止,在java 中向其他代碼傳遞一段代碼並不是很容易的。你不得不構建一個屬於某個類的對象,由它的某個方法來包含所需的代碼。

我們看看使用lambda表達式重寫上面的方法

        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("doWork" + i);
            }
        }).start();

lambda表達式語法

一般語法

(Type1 param1,Type2 params,...) -> {

    statment1;
    statment2;
    .....
    return statmentM;
    
}

單參數語法

可以省略前面的小括號,但是我一般都是帶着

param1 ->{
    ...
    ...
    return ...;
}

單語句語法

可以省略后面的大括號

param1 -> statment

函數式接口

在java中有許多已有的接口都需要封裝代碼塊,如Runnable。lambda表達式與這些接口都是向后兼容的。

對於只包含一個抽象方法的接口,你可以通過lambda表達式來創建該接口的對象。這種接口被稱為函數式接口。

這里注意一點,大家都知道接口中的方法是抽象的。事實上,接口經常會重新聲明Object類中的方法。如toString等 這些方法命名並不是抽象的。

我們看下Runnable的代碼 源碼

@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();
}

注意有個@FunctionalInterface 注解,有2個作用

  • 編譯器會檢查標注該注解的實體,檢查它是否是只包含一個抽象方法的接口。
  • 在jacadoc頁面也會包含一條聲明,說明這個接口是一個函數式接口。

但是這個注解並不是強制使用,從概念上講,所有只含有一個抽象方法的接口都是函數式接口,但是使用@FunctionalInterface 注解會讓你的代碼更加清楚,畢竟代碼的可讀性是編程的第一規范。

方法引用

有時候,你想要傳遞給其他代碼的操作已經有實現的方法。

Class or instance :: method

比如

(x) ->  System.out.println(x);

就等同於

 System.out::println;

構造器引用

  • 構造器引用同方法引用類似,不同的是在構造器引用中方法名是 new.

  • 對於擁有多個構造器的類,選擇使用哪個構造器取決於上下文

Class :: new

變量作用域

外部變量在 lambda 表達式引用時,jdk 8 編譯器會隱式做為 final 來處理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM