使用Java时的一些坑

Arrays.asList 存在的坑

阿里巴巴java开发规范说到使用工具类Arrays.asList()方法把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException

示例

1
2
3
4
5
6
public static void main(String[] args) {
List<String> list = Arrays.asList("F", "r", "e", "y", "a");
// list.clear();
// list.remove("a");
list.add("h");
}

执行以上三个方法中任何一个都会报以下异常

1
2
3
4
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
   ……

原因

点进去Arrays.asList,实现如下:

1
2
3
4
5
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}

这个 ArrayList 并不是我们平时用的ArrayList。而是Arrays里面的一个内部类。如下:

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
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;

ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}

@Override
public int size() {
return a.length;
}

@Override
public Object[] toArray() {
return a.clone();
}

@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

@Override
public E get(int index) {
return a[index];
}

@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}

@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}

@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}

@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}

@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}

@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
E[] a = this.a;
for (int i = 0; i < a.length; i++) {
a[i] = operator.apply(a[i]);
}
}

@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}

这个内部类没有addclearremove方法,所以抛出的异常其实来自于AbstractList。点进去就会发现抛出异常的地方,clear底层也会调用到remove所以也会抛出异常。如下:

1
2
3
4
5
6
7
public void add(int index, E element) {
throw new UnsupportedOperationException();
}

public E remove(int index) {
throw new UnsupportedOperationException();
}

填坑

Arrays.asList()底层其实还是数组。如果使用了Arrays.asList()的话,最好不要使用其集合的操作方法。如果想要使用,List<String> list = new ArrayList<>(Arrays.asList("F", "r", "e", "y", "a"))可以在外面这样包一层真正的ArrayList。

StringBuilder 存在的坑

1
2
3
4
5
6
7
public static void main(String[] args) {
// StringBuffer一样
       StringBuilder sb = new StringBuilder();
       Object obj = null;
sb.append(obj);
System.out.println(sb);
}

上面示例代码最后会打印 “null”,和你想要的可能不一样。

1
2
3
null

Process finished with exit code 0

原因参考 append() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}

@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}

/**
* Returns the string representation of the {@code Object} argument.
*
* @param obj an {@code Object}.
* @return if the argument is {@code null}, then a string equal to
* {@code "null"}; otherwise, the value of
* {@code obj.toString()} is returned.
* @see java.lang.Object#toString()
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}