Lists.transform注意问题

public class ListsTransformTest {

    public PersonVo personDbToVo(PersonDb personDb) {
        Preconditions.checkNotNull(personDb, "[PersonDbToVo]personDb为null");
        PersonVo personVo = new PersonVo();
        personVo.setName(personDb.getName() + ",from Db");
        personVo.setAge(personDb.getAge());
        personVo.setMsg(personDb.getMsg());
        return personVo;
    }

    @Test
    public void testListsTransform() {
        List<PersonDb> personDbs = Lists.newArrayList(new PersonDb("zhangsan", 20),
                new PersonDb("lisi", 24), new PersonDb("wangwu", 30));
        List<PersonVo> personVos = Lists.transform(personDbs, new Function<PersonDb, PersonVo>() {
            @Override
            public PersonVo apply(PersonDb personDb) {
                return personDbToVo(personDb);
            }
        });
        System.out.println(JacksonUtil.encode(personVos));
        for(PersonDb personDb : personDbs) {
            personDb.setMsg("hello world!");
        }
        System.out.println(JacksonUtil.encode(personVos));
        for(PersonVo personVo : personVos) {
            personVo.setMsg("Merry Christmas!");
        }
        System.out.println(JacksonUtil.encode(personVos));
    }
}
class PersonDb {
    private String name;
    private int age;
    private String msg;
    public PersonDb(String name, int age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("name", name)
                .add("age", age)
                .add("msg", msg).toString();
    }
}
class PersonVo {
    private String name;
    private int age;
    private String msg;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("name", name)
                .add("age", age)
                .add("msg", msg).toString();
    }
}

执行结果是

[{"name":"zhangsan,fromDb","age":20},{"name":"lisi,fromDb","age":24},{"name":"wangwu,fromDb","age":30}]

[{"name":"zhangsan,fromDb","age":20,"msg":"hello world!"},{"name":"lisi,fromDb","age":24,"msg":"hello world!"},{"name":"wangwu,fromDb","age":30,"msg":"helloworld!"}]

[{"name":"zhangsan,fromDb","age":20,"msg":"helloworld!"},{"name":"lisi,fromDb","age":24,"msg":"helloworld!"},{"name":"wangwu,fromDb","age":30,"msg":"helloworld!"}]

原因:
**通过Lists.transform()处理得到的list,处理前的元素变化会直接影响处理后的元素。并且处理得到元素列表赋值不会产生变化。原因是它生产返回的list并不是java.util的list而是TransformingRandomAccessList 或者TransformingSequentialList;然而在调用这两个List里面的get方法时内部源码是:
@Override public T get(int index) {
return function.apply(fromList.get(index));
}
重写了原来List的get方法。所以说每次get的时候都是把待处理的集合的元素作为apply方法的参数传入。所以就可以解释上面的问题。**
可以通过复制新的List来解决这一问题。guava对list的transform要到使用的时候在做转换,所以返回的只是一个List<…> 的包装类,真正的转换延迟到使用的时候再执行。如果你假定转换一定进行 而 忽略返回的结果,就会产生问题。一般的策略就是强制使用转换结果确保转换一定进行,可以复制新的 newArrayList 。
“`
/**
* Returns a list that applies {@code function} to each element of {@code
* fromList}. The returned list is a transformed view of {@code fromList};
* changes to {@code fromList} will be reflected in the returned list and vice
* versa.
*
*

Since functions are not reversible, the transform is one-way and new
* items cannot be stored in the returned list. The {@code add},
* {@code addAll} and {@code set} methods are unsupported in the returned
* list.
*
*

The function is applied lazily, invoked when needed. This is necessary
* for the returned list to be a view, but it means that the function will be
* applied many times for bulk operations like {@link List#contains} and
* {@link List#hashCode}. For this to perform well, {@code function} should be
* fast. To avoid lazy evaluation when the returned list doesn’t need to be a
* view, copy the returned list into a new list of your choosing.
*
*

If {@code fromList} implements {@link RandomAccess}, so will the
* returned list. The returned list is threadsafe if the supplied list and
* function are.
*
*

If only a {@code Collection} or {@code Iterable} input is available, use
* {@link Collections2#transform} or {@link Iterables#transform}.
*
*

Note: serializing the returned list is implemented by serializing
* {@code fromList}, its contents, and {@code function} – not by
* serializing the transformed values. This can lead to surprising behavior,
* so serializing the returned list is not recommended. Instead,
* copy the list using {@link ImmutableList#copyOf(Collection)} (for example),
* then serialize the copy. Other methods similar to this do not implement
* serialization at all for this reason.
*/
@CheckReturnValue
public static

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值