java8 Lambda表達式用法

什麼是函數式編程

函數式編程(英語:functional programming)又稱函數程序設計和泛函編程,是一種編程範型,它將電腦運算視爲數學上的函數計算,並且避免使用程序狀態以及易變對象。函數編程語言最重要的基礎是λ演算(lambda calculus)。而且λ演算的函數可以接受函數當作輸入(引數)和輸出(傳出值)。

函數式風格優點

1、代碼簡潔

通常情況下,函數式編程更加簡明扼要,精簡的代碼更易於維護。而Java代碼的冗餘性也是出了名的,大部分對於Java語言的攻擊都會直接針對Java繁瑣,而且死板的語法(不過這也不是缺點),然而,引入函數式編程範式後,這種情況發生了改變。我們可以讓Java用更少的代碼完成更多的工作。

代碼塊

Java

    static int[] arr = {1,3,4,5,6,7,8,9,10};      
    //傳統的處理方式:        
    for(int i=0;i<arr.length;i++){               
      if(arr[i]%2 != 0){                  
        arr[i]++;               
      }               
      System.out.println(arr[i]);      
    }  
    //函數式處理方式:  
    arr.stream().map(x->(x%2==0?x:x+1)).foreach(System.out::println);

2、易於多線程

由於對象都處於不變的狀態,因此函數式編程更加易於並行。實際上,你甚至完全不用擔心線程安全的問題。我們之所以要關注線程安全,一個很大的原因是當多個線程對同一個對象進行寫操作時,容易“使得對象狀態不一致”。但是,由於不變模式的存在,對象自創建以來,就不可能發生改變,因此,在多線程環境下,也就沒有必要進行任何同步操作。這樣不僅有利於並行化,同時,在並行化後,由於沒有同步和鎖機制,其性能也會比較好。例如java.lang.String對象。很顯然,String對象可以在多線程中很好的工作,但是,得益於不變模式,它的每一個方法都沒有進行同步處理。

3、可讀性更高

函數式編程風格只需要聲明計算機需要幹什麼事,而不是像命令式風格一樣將計算機的操作具體到每一步,所以可讀性會更高。

常用Lambda表達式

1.替代匿名內部類

毫無疑問,lambda表達式用得最多的場合就是替代匿名內部類,而實現Runnable接口是匿名內部類的經典例子。lambda表達式的功能相當強大,用()->就可以代替整個匿名內部類!請看代碼:

如果使用匿名內部類:

代碼塊

Java

@Test
    public void oldRunable() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("The old runable now is using!");
            }
        }).start();
    }

而如果使用lambda表達式:

代碼塊

Java

@Test
    public void runable() {
        new Thread(() -> System.out.println("It's a lambda function!")).start();
    }

2.使用lambda表達式對集合進行迭代

Java的集合類是日常開發中經常用到的,甚至說沒有哪個java代碼中沒有使用到集合類。。。而對集合類最常見的操作就是進行迭代遍歷了。請看對比:

代碼塊

Java

@Test
    public void iterTest() {
        List<String> languages = Arrays.asList("java","scala","python");
        //before java8
        for(String each:languages) {
            System.out.println(each);
        }
        //after java8
        languages.forEach(x -> System.out.println(x));
        languages.forEach(System.out::println);
    }

3.用lambda表達式實現map

一提到函數式編程,一提到lambda表達式,怎麼能不提map。。。沒錯,java8肯定也是支持的。請看示例代碼:

代碼塊

Java

@Test
    public void mapTest() {
        List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
        cost.stream().map(x -> x + x*0.05).forEach(x -> System.out.println(x));
    }

map函數可以說是函數式編程裏最重要的一個方法了。map的作用是將一個對象變換爲另外一個。在我們的例子中,就是通過map方法將cost增加了0,05倍的大小然後輸出。

4.用lambda表達式實現map與reduce

既然提到了map,又怎能不提到reduce。reduce與map一樣,也是函數式編程裏最重要的幾個方法之一。。map的作用是將一個對象變爲另外一個,而reduce實現的則是將所有值合併爲一個,reduce方法允許我們用自己的方式去計算元素或者將一個Stream中的元素以某種規律關聯

代碼塊

Java

@Test
    public void mapReduceTest() {
        List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
        double allCost = cost.stream().map(x -> x+x*0.05).reduce((sum,x) -> sum + x).get();
        System.out.println(allCost);
    }

最終的結果爲:63.00

5.filter操作

filter也是我們經常使用的一個操作。在操作集合的時候,經常需要從原始的集合中過濾掉一部分元素。

代碼塊

Java

@Test
    public void filterTest() {
        List<Double> cost = Arrays.asList(10.0, 20.0,30.0,40.0);
        List<Double> filteredCost = cost.stream().filter(x -> x > 25.0).collect(Collectors.toList());
        filteredCost.forEach(x -> System.out.println(x));
    }

最終結果:30 40

6.與函數式接口Predicate配合

除了在語言層面支持函數式編程風格,Java 8也添加了一個包,叫做 java.util.function。它包含了很多類,用來支持Java的函數式編程。其中一個便是Predicate,使用 java.util.function.Predicate 函數式接口以及lambda表達式,可以向API方法添加邏輯,用更少的代碼支持更多的動態行爲。Predicate接口非常適用於做過濾。

代碼塊

Java

public static void filterTest(List<String> languages, Predicate<String> condition) {
        languages.stream().filter(x -> condition.test(x)).forEach(x -> System.out.println(x + " "));
    }
    public static void main(String[] args) {
        List<String> languages = Arrays.asList("Java","Python","scala","Shell","R");
        System.out.println("Language starts with J: ");
        filterTest(languages,x -> x.startsWith("J"));
        System.out.println("\nLanguage ends with a: ");
        filterTest(languages,x -> x.endsWith("a"));
        System.out.println("\nAll languages: ");
        filterTest(languages,x -> true);
        System.out.println("\nNo languages: ");
        filterTest(languages,x -> false);
        System.out.println("\nLanguage length bigger three: ");
        filterTest(languages,x -> x.length() > 4);
    }

可以看到,Stream API的過濾方法也接受一個Predicate,這意味着可以將我們定製的 filter() 方法替換成寫在裏面的內聯代碼。

7.Match(匹配)

用來判斷某個predicate是否和流對象相匹配,最終返回Boolean類型結果,例如

代碼塊

JSON

    List<String> list = new ArrayList<String>();
    list.add("a1");
    list.add("b1");

 
    // 流對象中只要有一個元素匹配就返回true
    boolean anyStartWithA = list.stream().anyMatch((s -> s.startsWith("a")));
    System.out.println(anyStartWithA);
    // 流對象中每個元素都匹配就返回true
    boolean allStartWithA = list.stream().allMatch((s -> s.startsWith("a")));
    System.out.println(allStartWithA);

8.Limit(限制)

imit 方法用於獲取指定數量的流。 以下代碼片段使用 limit 方法打印出 10 條數據:

代碼塊

JSON

@Test
public void streamSortedTest() {
    Random random = new Random();
    random.ints().limit(10).sorted().forEach(System.out::println);
}

9.compare(排序)

代碼塊

JSON

list.compare((a,b)->a-b); 升序
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章