Java基礎(chǔ)之lambda表達式(JDK1.8新特性)

文章目錄

    Lambda表達式
    各種函數(shù)式接口
        Lambda的語法
        Lambda 表達實例
        舉例說明
        變量作用域
        處理lambda 表達式
        變量作用域
        函數(shù)式接口
            使用實例1
            使用實例2
            使用示例3(集合排序)
            使用示例4(按照對象屬性給list排序)
    總結(jié)
    參考

Lambda表達式

Lambda表達式允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進方法中)。函數(shù)式接口有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。函數(shù)式接口可以被隱式轉(zhuǎn)換為lambda表達式。
各種函數(shù)式接口

java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter

JDK1.8 新增加的函數(shù)接口:

java.util.function

java.util.function 包下包含了很多類,用來支持Java的函數(shù)式編程
在這里插入圖片描述

Lambda的語法

(parameters) -> expression

(parameters) ->{ statements; }


可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識別參數(shù)值
可選的參數(shù)圓括號:一個參數(shù)無需定義圓括號,但多個參數(shù)需要定義圓括號
可選的大括號:如果主體包括了一個語句,就不需要使用大括號
可選的返回關(guān)鍵字:如果主體只有一個表達式返回值,則編譯器會自動返回值,大括號需要指明表達式返回的一個數(shù)值。

Lambda 表達實例

    //1. 不需要參數(shù),返回值為5
    ()->5;
    //2. 接收一個參數(shù)(數(shù)字類型),返回其2倍的值
    x ->2*x
    //3.接受2個參數(shù)(數(shù)字),并返回他們的差值
    (x,y)->x - y;
    //4.接收2個int型整數(shù),返回他們的和
    (int x,int y)->x+y;
    //5. 接收一個String對象,并在控制臺打印,不返回任何值
    (String s)->System.out.print(s);

舉例說明

public class Java8Tester {
public static void main(String[] args) {
Java8Tester tester = new Java8Tester();

    //類型聲明
    MathOperation addition = (int a, int b) -> a + b;
    //不用聲明類型
    MathOperation subtraction = (a, b) -> a - b;
    //大括號中的返回語句
    MathOperation multipliaction = (int a, int b) -> {
        return a * b;
    };
    //沒有大括號及返回語句
    MathOperation division = (int a, int b) -> a / b;

    System.out.println("10+5=" + tester.operate(10, 5, addition));
    System.out.println("10-5=" + tester.operate(10, 5, subtraction));
    System.out.println("10*5=" + tester.operate(10, 5, multipliaction));
    System.out.println("10/5=" + tester.operate(10, 5, division));

    //不用括號
    GreetingService greetingService1 = message -> System.out.println("Hello " + message);

    //用括號
    GreetingService greetingService2 = (message) -> System.out.println("Hello " + message);

    greetingService1.sayMessage("Runoob");
    greetingService2.sayMessage("Google");
 }
interface MathOperation{
    int operation(int a, int b);
}
interface GreetingService{
    void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation) {
    return mathOperation.operation(a, b);
}

}

變量作用域

lambda 表達式只能引用標(biāo)記了final的外層局部變量,也就是說不能再lambda內(nèi)部修改定義在域外的局部變量,否則會編譯報錯。 在lambda表達式中,只能引用值不會改變的變量。 這是因為如果在lambda表達式中改變變量,并發(fā)執(zhí)行多個動作時就會不安全。對于目前為止我們看到的動作不會發(fā)生這種情況。

public class Java8Test2 {
final static String salutation = “Hello!”;

public static void main(String[] args) {
    GreetingService greetingService = message -> System.out.println(salutation + message);
    greetingService.sayMessage("Runoob");
}

interface GreetingService {
    void sayMessage(String message);
}

}

處理lambda 表達式

使用lambda表達式的重點是延遲執(zhí)行。畢竟,如果想要立即執(zhí)行代碼,完全可以直接執(zhí)行,而無需把它包裝在一個
lambda表達式中。之所以希望以后執(zhí)行代碼,這有很多原因,如:

在一個單獨的線程中運行代碼:
多次運行代碼;
在算法的適當(dāng)位置運行代碼(例如:排序中的比較操作);
發(fā)生某種情況時執(zhí)行代碼(如,點擊了一個按鈕,數(shù)據(jù)到達,等等);
只在必要時才運行代碼。

例如:假設(shè)你想要執(zhí)行一個動作n次,將這個動作和重復(fù)次數(shù)傳遞到一個 repeat 方法:
repeat(10,()->System.out.println(“Hello,world”))
要接受這個lambda表達式,需要選擇一個函數(shù)式接口。例如,我們可以使用 Runnable 接口:

public static void repeat(int n,Runnable action){
for(int i=0;i<n;i++){
action.run();
}
}

如果要告訴動作出現(xiàn)在某次迭代中。

/**
* 在某次迭代中執(zhí)行動作
* @param n
* @param action
*/
public static void repeat(int n, IntConsumer action) {
for (int i = 0; i < n; i++) {
action.accept(i);
}
}

變量作用域

lambda 表達式有3個部分

一個代碼塊;
參數(shù);
自由變量的值,這里指非參數(shù)而且不在代碼中定義的變量。
  • 1
  • 2
  • 3

函數(shù)式接口

函數(shù)接口,是指內(nèi)部只有一個抽象方法的接口。但是可以有多個非抽象方法的接口,函數(shù)式接口可以被隱式轉(zhuǎn)換為lambda表達式。
使用實例1

public class PredicateTest {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        /**
         *
         * Predicate<Integer> dispatcher = n -> true;
         n 是一個參數(shù)傳遞到Predicate接口的test方法
         n 如果存在test方法返回true
         */
        System.out.println("輸出所有數(shù)據(jù):");
        //傳遞參數(shù)n
        eval(list, n -> true);

//        Predicate<Integer> dispatcher = n -> true;
//        n 是一個參數(shù)傳遞到Predicate接口的test方法
//        如果n%2為0,test方法返回true
        System.out.println("******輸出所有的偶數(shù):");
        eval(list, n -> n % 2 == 0);

//        Predicate<Integer> predicate2=n->n>3
//        n是一個參數(shù)傳遞到Predicate接口的test方法
//        如果n大于3 test方法返回true
        System.out.println("輸出大于3的所有數(shù)字:");
        eval(list, n -> n > 3);
    }

    public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for (Integer n : list) {
            if (predicate.test(n)) {
                System.out.println(n+" ");
            }
        }
    }
}

 

使用實例2

public class CompareTest {

    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "pear");

        compareLength("apple", "banana", (n1, n2) -> -1);

        compareLength("banana", "pear", (n1, n2) -> 1);

        compareLength("banana", "banana", (n1, n2) -> 0);


        words.sort(Comparator.comparingInt(String::length));
    }

    public static void compareLength(String n1, String n2, Comparator comparator) {
        if (comparator.compare(n1, n2) == 0) {
            System.out.println("n1==n2" + n1 + "  " + n2);
        }
        if (comparator.compare(n1, n2) > 0) {
            System.out.println("n1>n2" + n1 + "  " + n2);
        }
        if (comparator.compare(n1, n2) < 0) {
            System.out.println("n1<n2" + n1 + "  " + n2);
        }

    }

}

使用示例3(集合排序)

現(xiàn)在我們有一個集合list,集合的里的數(shù)據(jù)類型是HashMap。那么我們?nèi)绾胃鶕?jù)HashMap中的某個key給list排序呢?

public class ListSortTest {
    public static void main(String[] args) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("id", 2);
        map1.put("name", "張二");
        list.add(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("id", 1);
        map2.put("name", "張一");
        list.add(map2);
        Map<String, Object> map3 = new HashMap<>();
        map3.put("id", 3);
        map3.put("name", "張三");
        list.add(map3);
        //升序排列
        Collections.sort(list, (o1, o2) -> {
            int o1Id = (int) o1.get("id");
            int o2Id = (int) o2.get("id");
            if (o1Id > o2Id) {
                return 1;
            } else {
                return -1;
            }
        });
        //降序排列
        Collections.sort(list, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                int o1Id = (int) o1.get("id");
                int o2Id = (int) o2.get("id");
                if (o1Id > o2Id) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });
    }
}

使用示例4(按照對象屬性給list排序)

public class ListSortTest2 {
    public static void main(String[] args) {
        Student student1 = new Student(1, "張三");
        Student student2 = new Student(2, "李四");
        List<Student> studentList = new ArrayList<>();
        studentList.add(student1);
        studentList.add(student2);

        //升序
        studentList.sort((o1, o2) -> {
            int o1Id = o1.getId();
            int o2Id = o2.getId();
            if (o1Id > o2Id) {
                return 1;
            } else {
                return -1;
            }
        });

        //降序
        studentList.sort((o1, o2) -> {
            int o1Id = o1.getId();
            int o2Id = o2.getId();
            if (o1Id > o2Id) {
                return -1;
            } else {
                return 1;
            }
        });
    }

總結(jié)

本文詳細(xì)介紹了lambda表達式,lambda表達式是JDK1.8最重要的特性?;旧纤械膬?nèi)部類都可以用lambda表達式來表示。靈活的運用lambda表達式和函數(shù)式接口可以大大的簡化的程序開發(fā)。
參考

Java 8 Lambda 表達式
Java 8 函數(shù)式接口





作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥