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 

猜你喜欢

转载自blog.csdn.net/weixin_41649106/article/details/87870457