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