Guava Lists.transform的一个小坑

    最近在修改项目中bug的时候遇到一个问题,需要修改一个list里的值,但是不管怎么set值,最后序列化的结果都是原来的值。百思不得其解,最后点开返回list的代码,看到里面用了Guava的Lists.transform做了类型转换,才恍然大悟。因为之前听说过Guava的Lists.transform方法有个坑,于是趁机研究下源码。

1public static <F, T> List<T> transform(List<F> fromList, Function<? super F, ? extends T> function) { 2 return (fromList instanceof RandomAccess) ? new TransformingRandomAccessList<>(fromList, function) : new TransformingSequentialList<>(fromList, function); 3}

源码中transform方法创建了TransformingRandomAccessList或者TransformingSequentialList,并将原始list和转换function传入,这两个类都是AbstractList的子类,并重写了几个关键方法:

@Override public T get(int index) { return function.apply(fromList.get(index));//获取原始list对应的元素,调用function转换 }

@Override public Iterator<T> iterator() { return listIterator();//调用父类AbstractList的listIterator,相当于调用listIterator(0) }

@Override public ListIterator<T> listIterator(int index) { return new TransformedListIterator<F, T>(fromList.listIterator(index)) { @Override T transform(F from) { return function.apply(from); } }; }

可以看到get方法是先从原始list里取出元素,然后调用传入的function转换,返回结果。而iterator方法,则是返回了TransformedListIterator,这个类实现了Iterator接口,其中最主要的是next方法:

@Override public final T next() { return transform(backingIterator.next()); }

先获取原始list的iterator的下个值,然后调用transform,使用传入function转换类型。

所以Lists.transform创建的List只有在真正获取元素的时候才会执行转换,也就是延迟加载,而且是每次取都重新执行一次转换也就是获取新的对象。这就是为什么对transform结果的修改并不会起效。

解决这个问题,只需要使用lambda即可

List<Integer> src = new ArrayList<>(); List<String> to = src.stream().map(e -> e.toString()).collect(Collectors.toList());

如果非要用Guava,需要把transform的结果copy一次,转换成普通的List:

List<String> list = Lists.transform(...) ArrayList<String> target = new ArrayList<>(Arrays.asList(new String[list.size()])); Collections.copy(target,list);

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

java8新特性

Stream将List转换为Map,使用Collectors.toMap方法进行转换背景:User类,类中分别有id,name,age三个属性。List集合,userList,存储User对象1、指定keyvalue,value是对象中的某个属性值。 Map<Integer,StringuserMap1userList.str