Lambda表达式使用示例

1,707 阅读5分钟

前言

Lambda表达式是 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数,也即是可以将函数作为参数传递到方法中。使用 Lambda 表达式可以使我们的代码变的更加简洁紧凑也更便于我们理解。

该文章仅仅只是记录一下本人在工作中用到的一些示例,不会介绍Lambda的一些底层原理, 如函数式接口、方法引用等。如果大家需要了解这些知识,还请各位自行查阅相关资料。 最近看到了一篇介绍Stream流的文章,很不错,推荐给大家:吃透JAVA的Stream流操作,多年实践总结

准备工作

为了便于后续示例的编写,需要首先定义一个实体类:

package com.learn.lambda;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class LambdaDemo {
    private String item;
    private Integer statNum;
    private String itemValue;
    /**
     * 扩展字段 写入任意信息
     */
    private Object extendInfo;

    public LambdaDemo(String item, Integer statNum) {
        this.item = item;
        this.statNum = statNum;
    }
}

初始化样例数据:

private static List<LambdaDemo> demoList = new ArrayList<>();
    static {
        LambdaDemo demo1 = new LambdaDemo("001",100);
        LambdaDemo demo2 = new LambdaDemo("002",200);
        LambdaDemo demo3 = new LambdaDemo("003",300);
        LambdaDemo demo4 = new LambdaDemo("004",400);
        LambdaDemo demo5 = new LambdaDemo("005",500);
        LambdaDemo demo6 = new LambdaDemo("006",600);
        LambdaDemo demo7 = new LambdaDemo("007",700);
        LambdaDemo demo8 = new LambdaDemo("008",800);
        LambdaDemo demo9 = new LambdaDemo("009",900);
        LambdaDemo demo10 = new LambdaDemo("010",1000);
        demoList.add(demo1);
        demoList.add(demo2);
        demoList.add(demo3);
        demoList.add(demo4);
        demoList.add(demo5);
        demoList.add(demo6);
        demoList.add(demo7);
        demoList.add(demo8);
        demoList.add(demo9);
        demoList.add(demo10);
    }

到此准备工作基本已经完成。

示例

List集合转为Map集合

转换成map是如果没有重复key的情况是可以使用下边的方式

/**
 * list转为Map
 */
public static void listToMap(){
    Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, LambdaDemo::getStatNum));
    collect.forEach((key,value)-> System.out.println(key+":"+value));
    
    //如果value 为空的话 可以进行下判断
    Map<String, Integer> map = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, p -> p.getStatNum() == null ? 0 : p.getStatNum()));
    System.out.println(map);
}
    

如果转换成map后有重复key值的话将会出现报错,将 样例数据 设置为有key值重复的情况。

LambdaDemo demo1 = new LambdaDemo("001",100);
LambdaDemo demo2 = new LambdaDemo("001",200);

再次执行上边的代码将会出现如下错误:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 100
	at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
	at java.util.HashMap.merge(HashMap.java:1254)
	at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
	at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)

解决该问题其实也很简单,如下是将重复key的value值相加,如果是String类型的话可以使用逗号隔开进行拼接。具体根据自己的实际业务需求进行相应的处理。

/**
 * list转为Map 解决重复key值的问题
 * 将值相加
 */
public static void listToMapSolveDuplicateKey(){
    Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, LambdaDemo::getStatNum,(oleValue,newValue)->oleValue+newValue));
    collect.forEach((key,value)-> System.out.println(key+":"+value));
}

运行输出结果为:

001:300     //001的值为300,说明已经将重复key值的value相加
003:300
004:400
005:500
006:600
007:700
008:800
009:900
010:1000

还可以进行覆盖操作:

/**
 * list转为Map 解决重复key值的问题
 * 将值覆盖
 */
public static void listToMapSolveDuplicateKey2(){
    Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, LambdaDemo::getStatNum,(oleValue,newValue)->newValue));
    collect.forEach((key,value)-> System.out.println(key+":"+value));
}

关键点就在于使用哪一个值,oleValue为第一个key对应的值,newValue为第二个相同key对应的值。

(oleValue,newValue)->newValue)
(oleValue,newValue)->oleValue)

List集合获取Map<String,List< LambdaDemo >>

使用groupingBy 进行分组

Map<String, List< LambdaDemo >> collect = demoList.stream().collect(Collectors.groupingBy(LambdaDemo::getItem));

此时map的value值存放的是对象的集合,如果想取出对象中的某一个属性作为集合返回,可以使用如下形式:

Map<String, List<String>> collect = demoList.stream()
.collect(Collectors.groupingBy(LambdaDemo::getItem,Collectors.mapping(LambdaDemo::itemValue,Collectors.toList())));

将实体类作为value值

Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, lambdaDemo->lambdaDemo));

或者如下形式

Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, Function.identity()));

计算对象中的某值之和

/**
 * list 计算对象中的某值之和
 */
public static void listSum(){
    int sum = demoList.stream().mapToInt(LambdaDemo::getStatNum).sum();
    System.out.println(sum);
}

除了mapToInt方法外,还有mapToDouble、mapToLong等方法。可以按需使用。

list转换为字符串

逗号也可以根据需求换成其他相关的符号

/**
 * 将list转换为使用逗号隔开的字符串
 */
public static void listToString(){
    String value = demoList.stream().map(lambdaDemo -> String.valueOf(lambdaDemo.getItem())).collect(Collectors.joining(","));
    System.out.println(value);
}

list转换为list

样例数据中的list中存放的是对象,我们可以将对对象中的item抽取出来转换成一个新的list

/**
 * list转换为list
 */
public static void listToList(){
    List<String> stringList = demoList.stream().map(LambdaDemo::getItem).collect(Collectors.toList());
    stringList.forEach(System.out::println);
}

删除数据

使用Lambda删除数据也是非常方便的:

/**
 * 删除数据
 */
public static void removeData(){
    demoList.removeIf(lambdaDemo->lambdaDemo.getItem().equals("001"));
    demoList.forEach(lambdaDemo -> System.out.println(lambdaDemo.getItem()));
}

排序

将样例数据中的statNum的数据打乱,可以使用如下方式进行排序:

/**
 * 排序
 */
public static void sortData() {
    //正序
    demoList.sort(Comparator.comparing(LambdaDemo::getStatNum));
    demoList.forEach(lambdaDemo -> System.out.println(lambdaDemo.getStatNum()));
    System.out.println("----------");
    //倒序
    demoList.sort(Comparator.comparing(LambdaDemo::getStatNum).reversed());
    demoList.forEach(lambdaDemo -> System.out.println(lambdaDemo.getStatNum()));
}

多字段排序

// 方式一 集合方式
 Collections.sort(userList, Comparator.comparing(UserVO::getName)
                .thenComparingInt(UserVO::getAge));
// 方式二 Stream方式
List<UserVO> collect = userList.stream()
            .sorted(Comparator.comparing(UserVO::getName).thenComparingInt(UserVO::getAge))
            .collect(Collectors.toList());

多字段Null 值排序

// 方式一 集合方式
Collections.sort(userList, Comparator.nullsFirst(Comparator.comparing(UserVO::getAge)).reversed());
// 方式二 Stream方式 nullsFirst() 有空的元素放在最前面,nullsLast(String::compareTo) 有空的字段放在最后面
List<UserVO> collect = userList.stream().sorted(Comparator.nullsFirst(Comparator.comparing(UserVO::getAge,Comparator.nullsLast(String::compareTo)))).collect(Collectors.toList());

JSONArray排序

JSONArray array = mtd.getJSONArray("XXXX");
array.sort(Comparator.comparing(obj -> ((JSONObject) obj).getString("XX")));

过滤

过滤也是比较常用的,比如我们过滤出statNum等于500的记录

    /**
     * 过滤
     */
    public static void filter(){
        Stream<LambdaDemo> lambdaDemoStream = demoList.stream().filter(lambdaDemo -> lambdaDemo.getStatNum() == 500);
        lambdaDemoStream.forEach(lambdaDemo -> {
            System.out.println(lambdaDemo.getStatNum());
        });

    }

去重

去重方式有很多,以下仅供参考!

List<LambdaDemo> distinctList = demoList.stream().collect(
        Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LambdaDemo::getItem))),
                ArrayList::new));
distinctList.forEach(System.out::println);
以上只是本人在当前工作中使用到的部分示例,意在做下简单记录以备忘记时及时查询。我会不定时更新,欢迎大家评论区补充!

逗号拼接字符串

public static <T> String parseListToStr3(List<T> list){
    String result = list.stream().map(String::valueOf).collect(Collectors.joining(","));
    return result;
}

自定义分页

List<String> receivers = new ArrayList<>();
for (int i = 1; i <= 100; i++) {
    receivers.add(String.valueOf(i));
}
int pageSize = 20;
int totalPage = receivers.size() % pageSize == 0 ? receivers.size() / pageSize : receivers.size() / pageSize + 1;
for (int pageNo = 1; pageNo <= totalPage; pageNo++) {
    List<String> subUserList = receivers.stream().skip((long) (pageNo - 1) * pageSize).limit(pageSize).
            collect(Collectors.toList());
    System.out.println(subUserList);
}