Lambda表達式的語法

1、Lambda 表達式語法

Lambda expressions address the bulkiness of anonymous inner classes by converting five lines of code into a single statement. This simple horizontal solution solves the “vertical problem” presented by inner classes.
Lambda表達式通過將五行代碼轉換爲單個語句來解決匿名內部類的龐大性。 這個簡單的水平解決方案解決了內部類提出的“垂直問題”。

在一個接口內存在一個方法的可以使用lambda 表達式比較簡潔
一個lambda表達式由三個部分組成

Argument List    Arrow Token    Body
(int x, int y)    ->    x + y
看一個簡單的例子:

(int x, int y) -> x + y

() -> 42

(String s) -> { System.out.println(s); }

第一個表達式使用兩個整數參數,分別命名爲x和y,並使用表達式形式返回x + y。
第二個表達式不接受任何參數,並使用表達式形式返回整數42.
第三個表達式接受一個字符串並使用塊形式將字符串輸出到控制檯,並且不返回任何內容。
2、lambda 表達式案例

2.1、Runnable Lambda

public class RunnableTest {

    @Test
    public void RunnableLambdaTest(){

        // 使用匿名內部類形式運行
        Runnable r1 = new Runnable() {
            public void run() {
                System.out.println("this is r1");
            }
        };

        // 執行內部方法, 並且沒有傳遞任何參數
        Runnable r2 = () -> System.out.println("this is r2");

        // 運行
        r1.run();
        r2.run();
    }
}

2.2、Comparator Lambda

public class ComparatorTest {

    @Test
    public void comparatorTest(){

        List<Person> personList = Person.createShortList();

        // 排序使用匿名內部類
        Collections.sort(personList, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getSurName().compareTo(o2.getSurName());
            }
        });

        System.out.println("=== Sorted Asc SurName ===");
        for(Person p : personList){
            p.printName();
        }

        // 使用lambda 表示是 asc
        System.out.println("=== Sorted Asc SurName ===");
        Collections.sort(personList, (p1, p2) -> p1.getSurName().compareTo(p2.getSurName()));
        for(Person p : personList){
            p.printName();
        }
    }
}
 

3、lambda 表達式和stream和集合

Stream是對集合的包裝, 通常和lambda一起使用。 使用lambda 可以支持許多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等 
具體案例如下 :

public class CollectionsTest {

    @Test
    public void lambdaListTest(){

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.forEach(s -> System.out.println(s));

        System.out.println("==================分割線====================");

        List<User> users = getUsers();
        users.forEach(u -> {
            System.out.println(u.getId() + " " + u.getName());
        });
    }

    /**
     *  先使用filter 過來一下, 在將滿足條件的遍歷打印
     */
    @Test
    public void lambdaFilterTest(){

        List<User> users = getUsers();
        users.stream()
                .filter(user -> (user.getAge() > 18))
                .forEach(user -> System.out.println(user.toString()));

    }

    /**
     * 自定義filter
     */
    @Test
    public void lambdaCustomFilterTest(){

        // 自定義filter
        Predicate<User> ageFilter = (u) -> (u.getAge() > 18);
        Predicate<User> nameFilter = (u) -> (u.getName().equals("name_1"));

        List<User> users = getUsers();
        users.stream()
                .filter(ageFilter)
                .filter(nameFilter)
                .forEach(u -> System.out.println(u.toString()));

    }

    /**
     * 使用limit限制顯示的集合個數
     */
    @Test
    public void lambdaLimiTest(){

        List<User> users = getUsers();
        users.stream()
                .limit(2)
                .forEach(user -> {
                    System.out.println(user.toString());
                });

    }

    /**
     * 根據名字的倒序操作
     */
    @Test
    public void lambdaSorted(){

        List<User> users = getUsers();
        users.stream()
                .sorted((u1, u2) -> (u2.getName().compareTo(u1.getName())))
                /**
                 * collect方法使用一個參數Collectors類來調用。
                 * Collectors類能夠根據流的結果返回List或Set。
                 * 該示例顯示瞭如何將流的結果分配給迭代的新List。
                 */
                .collect(Collectors.toList())
                .forEach(user -> System.out.println(user.toString()));

    }

    /**
     * 進行最大和最小, 年齡總和平均年齡
     */
    @Test
    public void minAndMaxLambdaTest(){

        List<User> users = getUsers();
        User user = users.stream().min((u1, u2) -> (u1.getAge() - u2.getAge())).get();
        System.out.println("年齡最小的是 : " + user.toString());

        User user1 = users.stream().max((u1, u2) -> (u1.getAge() - u2.getAge())).get();
        System.out.println("年齡最大的是 : " + user1.toString());

        int sum = users.stream().mapToInt((u) -> u.getAge()).sum();
        System.out.println("年齡總和 : " + sum);

        OptionalDouble average = users.stream().mapToDouble((u) -> u.getAge()).average();
        System.out.println("平均年齡 :" + average.getAsDouble());


        // summaryStatistics方法獲得stream 彙總數據。
        IntSummaryStatistics summaryStatistics = getUsers().stream().mapToInt((u) -> u.getAge()).summaryStatistics();
        System.out.println("==============分割線===============");
        System.out.println("最大年齡 : " + summaryStatistics.getMax());
        System.out.println("最小年齡 : " + summaryStatistics.getMin());
        System.out.println("平均年齡 : " + summaryStatistics.getAverage());
        System.out.println("年齡總和 : " + summaryStatistics.getSum());
        System.out.println("總的統計多少個人 : " + summaryStatistics.getCount());
    }


    /**
     * 構造用戶信息
     * @return
     */
    private List<User> getUsers(){

        List<User> users = new ArrayList<>();
        for (int i = 0; i < 3; i++){

            User u = new User();
            u.setName("name_" + i);
            u.setId("id_" + i);
            u.setAge(i + 18);
            users.add(u);
        }
        return users;
    }
}

4、Stream Collectors groupingBy

4.1、分組、統計、排序

案例一分組統計(基礎類型):
/**
 * 分組和統計
 */
@Test
public void listGroupSimpleTest(){

    /**
     * 基礎數據類型
     * 輸出結果:
     * 3 apple, 2 banana, papaya、orange 1
     */
    List<String> items = Arrays.asList("apple", "apple", "banana",
            "apple", "orange", "banana", "papaya");
    Map<String, Long> maps = items.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    System.out.println(maps);


    // 或者是直接forEach 直接打印
    items.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).forEach((k,v) ->{
        System.out.println(k + " : " + v);
    });
}

分組統計和排序(基礎類型)
/**
 * 基礎數據類型
 * 多一個排序功能
 */
@Test
public void listGroupSortTest(){

    //3 apple, 2 banana, others 1
    List<String> items = Arrays.asList("apple", "apple", "banana",
            "apple", "orange", "banana", "papaya");

    Map<String, Long> maps = items.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    Map<String, Long> finalMaps = new LinkedHashMap<>();
    maps.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).forEachOrdered(e -> finalMaps.put(e.getKey(), e.getValue()));
    System.out.println(finalMaps);

    // 直接輸入打印形式, 其中forEachOrdered ,降序
    items.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).forEachOrdered(e -> {
        System.out.println(e.getKey() + " : " + e.getValue());
    });
}

案例一分組統計(對象類型): 
‘group by’ a list of user defined Objects.
@Test
public void listGroupObject(){

   //3 apple, 2 banana, others 1
   List<Item> items = Arrays.asList(
           new Item("apple", 10, new BigDecimal("9.99")),
           new Item("banana", 20, new BigDecimal("19.99")),
           new Item("orang", 10, new BigDecimal("29.99")),
           new Item("watermelon", 10, new BigDecimal("29.99")),
           new Item("papaya", 20, new BigDecimal("9.99")),
           new Item("apple", 10, new BigDecimal("9.99")),
           new Item("banana", 10, new BigDecimal("19.99")),
           new Item("apple", 20, new BigDecimal("9.99")));

   // 通過名稱進行分組, 統計有多少個
   Map<String, Long> nameMaps = items.stream().collect(Collectors.groupingBy(Item::getName, Collectors.counting()));
   System.out.println(nameMaps);


   // 通過名稱分組, 質量求和
   Map<String, Integer> nqtsMaps = items.stream().collect(Collectors.groupingBy(Item::getName, Collectors.summingInt(Item::getQty)));
   System.out.println(nqtsMaps);
}

@Test
public void listGroupObjectMap(){

   //3 apple, 2 banana, others 1
   List<Item> items = Arrays.asList(
           new Item("apple", 10, new BigDecimal("9.99")),
           new Item("banana", 20, new BigDecimal("19.99")),
           new Item("orang", 10, new BigDecimal("29.99")),
           new Item("watermelon", 10, new BigDecimal("29.99")),
           new Item("papaya", 20, new BigDecimal("9.99")),
           new Item("apple", 10, new BigDecimal("9.99")),
           new Item("banana", 10, new BigDecimal("19.99")),
           new Item("apple", 20, new BigDecimal("9.99")));

   // 通過價格分組
   Map<BigDecimal, List<Item>> priceMaps = items.stream().collect(Collectors.groupingBy(Item::getPrice));
   System.out.println(priceMaps);

   // group by price, uses 'mapping' to convert List<Item> to Set<String>
   Map<BigDecimal, Set<String>> result  = items.stream().collect(Collectors.groupingBy(Item::getPrice, Collectors.mapping(Item::getName, Collectors.toSet())));
   System.out.println(result);

}

4.2 、分區

分區是一種特殊的分組,結果 map 至少包含兩個不同的分組——一個true,一個false。例如,按照價格分組: 
大於 N,另一組小於 N,使用 partitioningBy 收集器:

/**
 * 分區
 */
@Test
public void listGroupPartitionTest(){

    List<Item> items = Arrays.asList(
            new Item("apple", 10, new BigDecimal("9.99")),
            new Item("banana", 20, new BigDecimal("19.99")),
            new Item("orang", 10, new BigDecimal("29.99")),
            new Item("watermelon", 10, new BigDecimal("29.99")),
            new Item("papaya", 20, new BigDecimal("9.99")),
            new Item("apple", 10, new BigDecimal("9.99")),
            new Item("banana", 10, new BigDecimal("19.99")),
            new Item("apple", 20, new BigDecimal("9.99")));

    Map<Boolean, List<Item>> partitioned =
                    items.stream().collect(Collectors.partitioningBy(e -> e.getPrice().compareTo(new BigDecimal(20)) > 0));
    System.out.println(partitioned);

}

輸出如下結果: 
{false=[com.zzf.lambda.groupby.Item@6a6824be, com.zzf.lambda.groupby.Item@5c8da962, com.zzf.lambda.groupby.Item@512ddf17, com.zzf.lambda.groupby.Item@2c13da15, com.zzf.lambda.groupby.Item@77556fd, com.zzf.lambda.groupby.Item@368239c8], 
true=[com.zzf.lambda.groupby.Item@9e89d68, com.zzf.lambda.groupby.Item@3b192d32]}

你也可以將 groupingBy 收集器傳遞給 partitioningBy 收集器來將聯合使用分區和分組。例如,你可以統計每個分區中的每個水果的佔用數, 也就是比例:

/**
 * 分區2
 */
@Test
public void listGroupPartitionTest2(){

    List<Item> items = Arrays.asList(
            new Item("apple", 10, new BigDecimal("9.99")),
            new Item("banana", 20, new BigDecimal("19.99")),
            new Item("orang", 10, new BigDecimal("29.99")),
            new Item("watermelon", 10, new BigDecimal("29.99")),
            new Item("papaya", 20, new BigDecimal("9.99")),
            new Item("apple", 10, new BigDecimal("9.99")),
            new Item("banana", 10, new BigDecimal("19.99")),
            new Item("apple", 20, new BigDecimal("9.99")));

    // 分區和統計一起
    Map<Boolean, Map<String, Long>> result = items.stream().collect(Collectors.partitioningBy(e -> e.getPrice().compareTo(new BigDecimal(20)) > 0
            , Collectors.groupingBy(Item::getName, Collectors.counting())));

    System.out.println(result);

}                             

這樣會生成一個二級 Map: 
{false={papaya=1, banana=2, apple=3}, true={orang=1, watermelon=1}}

5、自定義

首先看看官方包的: java.util.function

java.util.function.BiFunction is a functional interface whose functional method is R apply(T t, U u). The BiFunction is interface represents an operation that takes two arguments (T and U) and returns a result R.
@Test
public void customTest(){

    BiFunction<String, String, String> f = new BiFunction<String, String, String>() {
        @Override
        public String apply(String s, String s2) {
            return s + s2;
        }
    };
    String apply = f.apply("a", "b");
    System.out.println("使用new的形式 : " + apply);

    /**
     *  1. 接受對象需要指定傳入類型, 一般存入類型是返回類型中的一項, 
     *   也可以不是, 具體可以參考java.util.function 下面的接口
     *  2. 還有就是{} 要返回的話要寫return, 否則不返回
     *  3. 如果是() 不用寫返回return 默認返回
     *  或者 都不寫 例如下面的Integer 形式的
     *  BiFunction<Integer, Integer, Integer> function2 = (a, b) ->   a + b;
     */
    BiFunction<String, String, String> function1 = (s1, s2) -> {
        String s3 = s1 + s2;
        return s3;
    };
    System.out.println(function1.apply("BORAJI", ".COM"));

    BiFunction<Integer, Integer, Integer> function2 = (a, b) -> a + b;
    System.out.println(function2.apply(100, 200));

}

很多時候需要有自己的邏輯所以需要自定義接口, 下面定義並且簡單使用:

@FunctionalInterface
public interface ZzfCustom<U, T> {

    public U getValue(T t);
}
使用:

@Test
public void zzfCustomTest(){

    ZzfCustom<String, String> objectStringZzfCustom = (String name) -> ("hello " + name);
    System.out.println(objectStringZzfCustom.getValue("zzf"));
}

參考地址 : 
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html 
https://www.boraji.com/java-8-bifunction-interface-example 
https://www.mkyong.com/java8/java-8-collectors-groupingby-and-mapping-example/
--------------------- 
轉自:https://blog.csdn.net/zhongzunfa/article/details/80668178 

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