guava集合类中神奇transform方法研究

之前我就提过guava这个东西,最近在项目中使用的越来越多,越来越发现这东西好神奇 ,用起来真顺手。不得不佩服,谷歌出品,必属精品。
平时业务开发中经常遇到需要转换List的需求。例如,假设现在有一个类如下:

1
2
3
4
5
6
class Customer{
private long id;
private String costomerName;

//below is getters and setters
}

然后有这样一个List<Customer> customerList的List,现在我想要一个包含Customerid的List: List<Long> customerIdList。那如何做呢?

笨笨的方法

1
2
3
4
5
6
List<Long> customerIdList = new ArrayList<>();
for(Customer customer: customerList){
Long customerId = new Long();
customerId = customer.getId();
customerIdList.add(customerId);
}

上面我通过6行代码,用for循环遍历了一遍才完成了这样的操作。来看看神奇的guava的做法。
神奇Guava的方法

1
2
3
4
5
6
7
List<Long> customerIdList = Lists.transform(customerList, new Function<Customer, Long>() {
@Nullable
@Override
public Long apply(WmMyCommentResult input) {
return input.getId();
}
});

一行代码搞定,屌屌的。
那Guava是不是其实就把for循环搬进了transform()方法里而已呢?如果是这样,也没太高明不是吗?
于是我看了看transform()方法,越看越佩服!不过看完后觉得其实总体思想也很简单,就是改写迭代器。
先看Lists.transform的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
public static <F, T> List<T> transform(
List<F> fromList, Function<? super F, ? extends T> function)
{

return (fromList instanceof RandomAccess)
? new TransformingRandomAccessList<F, T>(fromList, function)
: new TransformingSequentialList<F, T>(fromList, function);
}

/**
* Implementation of a sequential transforming list.
*
* @see Lists#transform
*/

private static class TransformingSequentialList<F, T>
extends AbstractSequentialList<T> implements Serializable {

final List<F> fromList;
final Function<? super F, ? extends T> function;

TransformingSequentialList(
List<F> fromList, Function<? super F, ? extends T> function) {
this.fromList = checkNotNull(fromList);
this.function = checkNotNull(function);
}
/**
* The default implementation inherited is based on iteration and removal of
* each element which can be overkill. That's why we forward this call
* directly to the backing list.
*/

@Override public void clear() {
fromList.clear();
}
@Override public int size() {
return fromList.size();
}
@Override public ListIterator<T> listIterator(final int index) {
final ListIterator<F> delegate = fromList.listIterator(index);
return new ListIterator<T>() {
@Override
public void add(T e) {
throw new UnsupportedOperationException();
}

@Override
public boolean hasNext() {
return delegate.hasNext();
}

@Override
public boolean hasPrevious() {
return delegate.hasPrevious();
}

@Override
public T next() {
return function.apply(delegate.next());
}

@Override
public int nextIndex() {
return delegate.nextIndex();
}

@Override
public T previous() {
return function.apply(delegate.previous());
}

@Override
public int previousIndex() {
return delegate.previousIndex();
}

@Override
public void remove() {
delegate.remove();
}

@Override
public void set(T e) {
throw new UnsupportedOperationException("not supported");
}
};
}

private static final long serialVersionUID = 0;
}

/**
* Implementation of a transforming random access list. We try to make as many
* of these methods pass-through to the source list as possible so that the
* performance characteristics of the source list and transformed list are
* similar.
*
* @see Lists#transform
*/

private static class TransformingRandomAccessList<F, T>
extends AbstractList<T> implements RandomAccess, Serializable {

final List<F> fromList;
final Function<? super F, ? extends T> function;

TransformingRandomAccessList(
List<F> fromList, Function<? super F, ? extends T> function) {
this.fromList = checkNotNull(fromList);
this.function = checkNotNull(function);
}
@Override public void clear() {
fromList.clear();
}
@Override public T get(int index) {
return function.apply(fromList.get(index));
}
@Override public boolean isEmpty() {
return fromList.isEmpty();
}
@Override public T remove(int index) {
return function.apply(fromList.remove(index));
}
@Override public int size() {
return fromList.size();
}
private static final long serialVersionUID = 0;
}

由上面可以看到,由于list分两种类型,ArrayListLinkedList,由于ArrayList是可以随机访问,而LinkedList不行,所以需要重写的方法不一样。
ArrayList使用function类重写下getremove方法即可。
LinkedList则直接重写ListIterator万事大吉。

不过这样的写法也让我打开眼界,对List的理解也又更进一步。