浅谈lambda表达式-Collectors.toMap

jdk自从8开始,添加了lambda表达式,为了兼容lambda表达式,所以对接口也做了修改,添加了default关键词。这是jdk8与7最大的一个变动。

自从有了lambda表达式之后,项目中被大量运用,但是对于我本人来讲,我其实是挺反对用lambda表达式的,我也一直不用它。原因有三:

其一,就是它虽然让代码变的简洁,但是简洁的结果就是造成语法并不为常人理解,我觉得它的语法上并不是通俗易懂的,需要翻看说明才能看的懂;

其二,没法调试,它采用流的方式进行处理,内存的逻辑根本没法调试;

其三,性能方面,对于数据量少,并发量不大的情况下,我觉得性能很差,这个文章后面也会简单的做下比较。有人说高并发大数据量会有性能优势,但是并发量要大到什么程度,数据量要大到什么程度,没有验证过。而且我们实际工作中,不会一次性处理大量数据,一般都会分页/分批处理。高并发也会进行请求的分发,实际到一台服务器上也不会有很大的并发。

那接下来简单介绍下lambda表达式中使用Collectors.toMap的例子,因为今天review代码的时候刚好注意到它了,就简单研究了下。

这个方法主要是用在我们一个list集合中的元素,要根据一定的条件,将list的集合中的元素内容,放到map集合中。直接上代码吧:

public class TestStream {

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person("zs","sssss"));
        list.add(new Person("zs","ddddd"));
        list.add(new Person("ls","sssss"));
        list.add(new Person("wk","wwwww"));

        long time1 = System.currentTimeMillis();
        //使用lambda表达式进行处理
        Map<String, String> resultMap = list.stream().collect(Collectors.toMap(Person::getName, item->item.getAddress(),(a, s)->s+","+a));
        long time2 = System.currentTimeMillis();
        //使用常规方法处理
        Map<String, String> result = new HashMap<>();
        for(Person p : list){
            result.put(p.getName(),result.get(p.getName()) == null? p.getAddress() : result.get(p.getName())+","+p.getAddress());
        }
        long time3 = System.currentTimeMillis();

        for(Map.Entry<String, String> entry : resultMap.entrySet()){
            System.out.println(entry.getKey()+"======="+entry.getValue());
        }
        System.out.println((time2-time1)+"======="+(time3-time2));
        for(Map.Entry<String, String> entry : result.entrySet()){
            System.out.println(entry.getKey()+"======="+entry.getValue());
        }
    }
}

class Person{
    private String name;
    private String address;

    public Person(String name, String address){
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

简单介绍下代码干了啥。代码中有个Person类,有name和address两个属性。 一个list集合中放了多个person对象,并且person对象有name重复,但是address不一样的记录。

现在要把list中的元素放到一个map集合中,key是name值,value是address值。 对于name重复的,让他们的address值合并到一个name中,用逗号隔开,存到map里。

lambda表达式用了一行就解决了。但是常规方法,用了四行代码。

lambda表达式将list先转化为stream()流,调用collect()方法,参数是个Collector。Collectors提供了很多返回Collector的静态方法,toMap就是其中之一。

toMap有三个参数,第一个是key生成的方法/函数,第二个是value生成的方法/函数,第三个是对于重复key的合并逻辑方法/函数。

对于第一和第二个参数,使用Person::getName() / Person::getAddress()方法也行,使用item->item.getName() / item -> item.getAddress()也行,这是两种方式。item是个代名词,你改成任何字母或者单词(关键词除外)标识都行。

对于第三个参数,(a,s)->a+","+s 这个段代码,是个条件函数,是处理对于重复key的情况下的合并处理逻辑。

其中a,s分别代表重复的两个name对应的address值,a/s只是个标识,你用其他任何字母代替都行,但是a和s是有顺序的,在(a,s)的写法中, a表示list集合中靠前的值,s是靠后的值。如果写成(s,a),那么s就是靠前的值,a就是靠后的值), 所以如果这个函数表达式写成 (a,s)->a ,意思就是如果遇到重复的name(因为map的key是不会重复的),那么map中value的值取排序靠前name对应的address值。 用上面的代码例子来说的话,最后map中key为zs的value值就是sssss。

如果写成(a,s)->s, 也就是如果遇到重复的name,那么map中value的值就是让后面的address覆盖前面的address。用上面的代码例子来说的话,最后map中key为zs的value值就是ddddd。

好了,toMap的介绍就到这里了。下面就看下性能吧。

直接看下我本地运行的例子的打印结果吧:

99是毫秒,也就是lambda表达式这一行,就运行了99ms,但是常规方法,四行运行了0ms。总共才4条数据,耗费了99ms。看到性能了么。99ms,对于一个接口来讲,意味着1秒钟也就支持10个左右的并发。这也是为什么我不太喜欢我们兄弟们使用lambda表达式最主要的原因。

言尽于此,对于jdk自己推出了lambda表达式,那么性能方面他们应该也会考虑去优化,对于朋友们用不用lambda表达式,还是根据自己的实际情况及意愿来吧。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值