Java 集合使用注意事项总结
https://javaguide.cn/java/collection/java-collection-precautions-for-use.html#%E5%BF%85%E7%9C%8B%E4%B8%93%E6%A0%8F
1. 集合判空
判断所有集合内部的元素是否为空,使用
isEmpty()
方法,而不是size()==0
的方式。
使用isEmpty()方法具有更好的可读性,时间复杂度为O(1);使用size()方法的时间复杂度不固定,在某些情况下可以达到O(n)。
2. 集合转Map
在使用
java.util.stream.Collectors
类的toMap()
方法转为Map
集合时,一定要注意当 value 为 null 时会抛 NPE 异常。
class Person1 {
String name;
String phoneNumber;
}
List<Person1> list = new ArrayList<>();
list.add(new Person1("jack", "123456"));
list.add(new Person1("bob", "456789"));
Map<String, String> collect = list.stream().collect(
Collectors.toMap(Person1::getName, Person1::getPhoneNumber)
);
/*
jack -> 123456
bob -> 456789
*/
3. 集合遍历
不要在 foreach 循环里进行元素的
remove/add
操作。remove 元素请使用Iterator
方式,如果并发操作,需要对Iterator
对象加锁。
fail-fast 机制 :多个线程对 fail-fast 集合进行修改的时候,可能会抛出
ConcurrentModificationException
。 即使是单线程下也有可能会出现这种情况,上面已经提到过。
Java8 开始,可以使用 Collection#removeIf()
方法删除满足特定条件的元素,
removeIf() 中,需要重写一个过滤器,可以用lambda表达式。
List<Integer> li = new ArrayList<>();
for (int i = 0; i < 10; i++) {
li.add(i);
}
li.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer % 2 == 0;
}
})
li.removeIf(t -> t % 2 == 0);
li.stream().forEach(t -> System.out.print(t + " "));
/*
1 3 5 7 9
*/
4. 集合去重
可以利用
Set
元素唯一的特性,可以快速对一个集合进行去重操作,避免使用List
的contains()
进行遍历去重或者判断包含操作。
set
的去重使用的是hash
值,单个元素去重的时间复杂度在没有哈希冲突时为O(1)
;list的contains()
方法去重采用的是迭代器去重,单个元素去重的时间复杂度最差情况下为O(n)
。
// Set 去重代码示例
public static <T> Set<T> removeDuplicateBySet(List<T> data) {
if (CollectionUtils.isEmpty(data)) {
return new HashSet<>();
}
return new HashSet<>(data);
}
// List 去重代码示例
public static <T> List<T> removeDuplicateByList(List<T> data) {
if (CollectionUtils.isEmpty(data)) {
return new ArrayList<>();
}
List<T> result = new ArrayList<>(data.size());
for (T current : data) {
if (!result.contains(current)) {
result.add(current);
}
}
return result;
}
5. 集合转数组
使用集合转数组的方法,必须使用集合的
toArray(T[] array)
,传入的是类型完全一致、长度为 0 的空数组
*注意:
toArray(T[] array)
方法的参数是一个泛型数组,如果 toArray
方法中没有传递任何参数的话返回的是 Object
类 型数组。
String [] s= new String[]{
"dog", "lazy", "a", "over", "jumps", "fox", "brown", "quick", "A"
};
List<String> list = Arrays.asList(s);
Collections.reverse(list);
//没有指定类型的话会报错
s=list.toArray(new String[0]);
new String[0]
作为方法参数,指定了泛型,大小为0是为了节省空间,因为其只是为了说明类型。
6. 数组转集合
使用工具类
Arrays.asList()
把数组转换成集合时,不能使用其修改集合相关的方法, 它的add/remove/clear
方法会抛出UnsupportedOperationException
异常。
*注意:
-
Arrays.asList()
转换得到的是Array类型,而不是List类型。因此不支持add/remove等方法。 -
Arrays.asList()
是泛型方法,因此传递的数组必须是对象数组,而不能是基本类型数组。
int[] myArray1 = {1, 2, 3};
Integer[] myArray2 = {1, 2, 3}; // 正确
List myList1 = Arrays.asList(myArray1);
List myList2 = Arrays.asList(myArray2);
System.out.println(myList1.size()); // 1 list得到的是对象本身
System.out.println(myList2.size()); // 3 list得到的是对象中的元素
如何正确的将数组转为List集合?
List list = new ArrayList<>(Arrays.asList("a", "b", "c"))
Integer [] myArray = { 1, 2, 3 };
List myList = Arrays.stream(myArray).collect(Collectors.toList());
//基本类型也可以实现转换(依赖boxed的装箱操作)
int [] myArray2 = { 1, 2, 3 };
List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());