List集合操作優化
JDK版本1.8
定義一個簡單的對象
// lombok註解
@Data
@AllArgsConstructor
public class Student {
private String name;
private int source;
}
初始化一個集合
List<Student> students = new ArrayList<>();
@Before
public void init10() {
students.add(new Student("小明1", 10));
students.add(new Student("小明2", 20));
students.add(new Student("小明3", 30));
students.add(new Student("小明4", 40));
students.add(new Student("小明5", 50));
students.add(new Student("小明6", 60));
students.add(new Student("小明7", 70));
students.add(new Student("小明8", 80));
students.add(new Student("小明9", 90));
students.add(new Student("小明1", 100));
}
刪除元素
for循環刪
用for循環刪除元素,如果用正序刪除元素,你在遍歷的時候漏會掉某些元素。比如當你刪除第1個元素後,繼續根據索引訪問第2個元素時,因爲刪除的關係後面的元素都往前移動了一位,所以實際訪問的是第3個元素。因此,這種方式可以用在刪除特定的一個元素時使用,但不適合循環刪除多個元素時使用。而用倒敘刪除就不會存在這種問題。
for (int i = students.size() - 1; i >= 0; i--) {
Student stu = students.get(i);
if (40 < stu.getSource() && stu.getSource() < 70) {
students.remove(i);
}
}
Iterator迭代器刪除
Iterator<Student> iter = students.iterator();
while (iter.hasNext()) {
Student stu = iter.next();
if (50 < stu.getSource() && stu.getSource() < 70) {
iter.remove();
// 如果在迭代裏面調用用源集合(students)remove(obj)方法會拋java.util.ConcurrentModificationException 異常
}
}
用Stream.filter過濾元素
List<Student> list = students.stream().filter(stu -> {
if (50 < stu.getSource() && stu.getSource() < 70) {
return false;
}
return true;
}).collect(Collectors.toList());
// fileter返回的是一個匹配的元素的Stream,原集合沒有變化,需調用collect 創建一個新的集合
刪除指定下標範圍
刪除一個集合下標n到m的值
推 薦
// 比如刪除students集合下標4到7的元素,前閉後開
students.subList(4, 7).clear();
// list的subList返回的是原集合的鏡像副本,對該返回的集合操作,會反應到原集合
性能測試
自用筆記本測試CPU: i5-6300U, 12G內存
測試是上面的方法,生成數據代碼如下:
int num = 1000;
Random random = new Random();
for (int i = 0; i < num; i++) {
// source隨機生成 0-100整數
students.add(new Student("學生" + i, random.nextInt(100)));
}
結果如下:
第一行是數據量,中間是3次平均耗時(毫秒)
可以看出,當數據量達到一定量級時,for循環和迭代器的性能下降明顯,也說明了java8的stream操作集合的強大。
其他操作
處理集合元素,併合並某些元素
例如學生集合裏面有名字相同的元素,需要把source*10,再進行合併:
@Test
public void test(){
// 如果數據量很大,用並行流parallelStream,需用 Collectors.toConcurrentMap
Map<String, Student> res = students.stream()
.collect(Collectors.toMap(Student::getName, valueMapper, mergeFunction));
// 打印結果集
res.values().forEach(System.out::println);
}
/**
* 對單個元素進行處理.
*/
public UnaryOperator<Student> valueMapper = t -> {
t.setSource(t.getSource()*10);
// TODO 其他業務操作
return t;
};
/**
* 合併元素,注意必須返回一個對象.
* 到這裏面的元素是keyMapper相同的元素,底層用equals比較
*/
private BinaryOperator<Student> mergeFunction = (t1, t2) ->{
t1.setSource(t1.getSource() + t2.getSource());
return t1;
};
Collectors
裏面還有其他很多方法,這裏就不一一講解了。
排序
根據集合對象單個屬性排序
- 實現Comparable 接口,重寫compareTo方法
@Data
@AllArgsConstructor
public class Student implements Comparable<Student> {
private String name;
private int source;
@Override
public int compareTo(Student o) {
return this.source > o.getSource() ? 1 : this.source < o.getSource() ? -1 : 0;
}
}
- 使用 Collections的sort方法
Collections.sort(students,new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getSource()>o2.getSource()? 1:o1.getSource()<o2.getSource()?-1:0;
}
});
students.stream().forEach(System.out::println);
根據集合對象指定多屬性排序
1.創建比較器,需要commons-beanutils.jar 和 commons-collections.jar
ArrayList<Comparator> sortFields = new ArrayList<>();
// 創建一個默認的比較強
Comparator mycmp = ComparableComparator.getInstance();
// 創建一個降序序比較器
mycmp = ComparatorUtils.nullHighComparator(mycmp);
// 按name 降序
sortFields.add(new BeanComparator("name", mycmp));
// 創建一個升序比較器
mycmp = ComparatorUtils.nullLowComparator(mycmp);
// 按source 升序
sortFields.add(new BeanComparator("source", mycmp));
// 它包裝了一個依次增加比較器,ComparatorChain依次調用每個比較器
ComparatorChain multiSort = new ComparatorChain(sortFields);
Collections.sort(students, multiSort);
// 打印排序結果
students.stream().forEach(System.out::println);
- java8的lambda表達式
List<Student> res = students.stream()
.sorted(
Comparator.comparing(Student::getName)
// 默認是升序排序,調用reversed() 方法降序
// 可以調用多個thenComparing(),進行排序
.thenComparing(Student::getSource))
.collect(Collectors.toList());
// 打印結果集
res.stream().forEach(System.out::println);