代碼優化-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 裏面還有其他很多方法,這裏就不一一講解了。

排序

根據集合對象單個屬性排序

  1. 實現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;

    }
}
  1. 使用 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);
  1. 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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章