Collection 翻下词典,有很多含义:
收集;聚集;(常指同类的)收藏品;募捐,募集;作品集;聚积;取走;一群人;拿走;(常为季节性推出的)系列时装(或家用品);一批物品
选择“聚集”作为翻译名,我以为可行,除非我们现在重新创造一个汉语词组。
对于CRUD和非CRUD,聚集都是一个无比重要的东西,因为计算机的本质是对信息的处理。
信息一般不是单个,是一堆,一堆堆,一块块,一个个....
网上关于聚集的资料无比多,所以本文主要是做一个简要的介绍,并添加一些注意事项和个人感悟。
一、简介
不外Collection的子孙过于多,用现有词汇命名这些子孙并不容易,有待创建新的词汇。
常用知名子孙有:
List -- 列表,javaDoc的释义是:有序聚集。
--ArrayList 动态大小列表 ,这是crud中最常用的范例 。不包管顺序
--LinkedList 双链列表,可以固定成员顺序。本身实现了Deque的接口,可用于辅助实现FiLo的算法
Set - 无重复聚集,允许有一个null成员
---TreeSet 有序聚集
-- HastSet 哈希聚集 ,主要是操纵的性能好一些
-- LinkedHashSet 双向链哈希聚集,保持了插入顺序,又具有对应的性能
Queue -队列
--Deque 双端操纵队列。它有一个著名的实现 LinkedList
Buffer --缓冲
不外这个主要是阿帕奇的实现org.apache.commons.collections.Buffer,算不得java的根本范例
如果是初级程序员,大概以CRUD为主的,那么只要学些掌握ArrayList就差不多了,因为现在的大部分的ORM大概JDBC的上级实现都适用ArrayList来存储数据集。
二、聚集的基本方法
仅仅介绍Collection的接口方法,为了便于理解,以LinkedList为例子。
这些方法都极其简单,也没有什么特别好解释的,直接上例子吧!- package study.base.types.collection.list;
- import java.util.*;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.stream.Collectors;
- /**
- * 演示Collection接口的基本操作和LinkedList的一些典型操作
- * @author lto
- */
- public class TestLinkedList {
- private LinkedList<MoneyJar> list;
- private String[] givers = new String[]{"爸爸","妈妈","哥哥","姐姐","爷爷","奶奶"};
- private Random random = new Random();
- private Map<String,Long> realGivers;
- public TestLinkedList(int size) {
- this.list = new LinkedList<>();
- this.realGivers = new HashMap<>();
- //插入100个MoneyJar,金额和日期都是随机的,giver是随机
- for (int i = 0; i < size; i++) {
- String giver = givers[random.nextInt(givers.length)];
- int amount = random.nextInt(100);
- this.list.add(new MoneyJar(giver, amount, new Date()));
- }
- //按照giver分组统计个数,并赋值给realGivers
- this.list.stream().collect(Collectors.groupingBy(MoneyJar::giver,
- Collectors.counting())).forEach((k,v)->{
- realGivers.put(k,(long)v);});
- //打印realGivers
- this.realGivers.forEach((k,v)->{System.out.println(String.format("%s共有%d个", k, v));});
- }
- public void count(){
- long start = System.currentTimeMillis();
- final long[] total = {0};
- this.list.spliterator().forEachRemaining(mj-> total[0] += mj.amount());
- System.out.println(String.format("总共%d元",total[0]));
- System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
- }
- public void sortByAmount(){
- this.list.sort((o1, o2) -> o1.amount().compareTo(o2.amount()));
- }
- /**
- * 统计每个giver给的钱,并打印结果
- */
- public void sumByGiver(){
- System.out.println("--------------------****************-----------------------------");
- //根据giver分组统计每个giver给的钱,并返回一个ListMap
- long start = System.currentTimeMillis();
- Map<String, Integer> result= this.list.stream().collect(Collectors.groupingBy(MoneyJar::giver,
- Collectors.summingInt(MoneyJar::amount)));
- //打印统计结果
- result.forEach((k,v)->{System.out.println(String.format("%s给的钱是%d", k, v));});
- System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
- //采用for循环的方式,分组统计
- System.out.println("采用for循环的方式,分组统计-----------------------------");
- long start1 = System.currentTimeMillis();
- Map<String,List<Integer>> result1= new HashMap<>();
- //初始化result1,把realGivers的每个元素作为key,初始值为0
- this.realGivers.forEach((k,v)->{
- result1.put(k,new ArrayList<>());
- });
- //遍历list,计算每个giver给的钱
- for (MoneyJar moneyJar : list) {
- result1.get(moneyJar.giver()).add(moneyJar.amount());
- }
- //根据result1的成员个数,创建对应的线程,然后在线程中计算每个giver给的钱,并计算总和
- int numThreads=result1.size();
- CountDownLatch latch = new CountDownLatch(numThreads);
- ExecutorService executor = Executors.newFixedThreadPool(numThreads);
- result1.forEach((k,v)->{
- Runnable worker = () -> {
- try {
- long sum=0;
- for (int i : v) {
- sum+=i;
- }
- System.out.println(String.format("%s给的钱是%d", k, sum));
- } finally {
- latch.countDown(); // 计数减一
- }
- };
- // 使用executor提交任务,而不是直接启动Thread
- executor.submit(worker);
- });
- try {
- // 等待所有线程完成
- latch.await();
- System.out.println("All threads have finished.");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // 关闭executor,释放资源
- executor.shutdown();
- System.out.println("耗费时间:"+(System.currentTimeMillis()-start1));
- }
- public void splitToSum(){
- //把钱罐的钱分为n份,分别统计,然后再合并总的金额,并统计耗费时间
- System.out.println("-- 采用并行流的方法");
- long start = System.currentTimeMillis();
- Long total=list.parallelStream().mapToLong(MoneyJar::amount).sum();
- System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
- System.out.println("总金额是"+total.toString());
- //采用传统的for循环方式累积
- System.out.println("-- 采用传统的for循环的方法");
- start = System.currentTimeMillis();
- long sum=0;
- for (MoneyJar moneyJar : list) {
- sum+=moneyJar.amount();
- }
- System.out.println("总金额是"+sum);
- System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
- }
- /**
- * 把小于等于指定的金额的钱都清理掉
- * @param amount
- */
- public void purgeSmallMoney(int amount){
- this.list.removeIf(moneyJar -> moneyJar.amount()<=amount);
- }
- record MoneyJar(String giver,Integer amount,
- Date putDay){
- }
- public static void main(String[] args) {
- //当10万个的时候,并行的速度反而是for的3倍左右。
- TestLinkedList test = new TestLinkedList(200);
- test.splitToSum();
- test.sortByAmount();
- System.out.println("-- 排序后 -----");
- for (MoneyJar moneyJar : test.list) {
- System.out.println(moneyJar);
- }
- //测试100万的情况
- TestLinkedList test100 = new TestLinkedList(1000000);
- test100.splitToSum();
- //测试2000万的情况
- TestLinkedList test1000 = new TestLinkedList(20000000);
- test1000.splitToSum();
- //以上三个例子,哈无例外,都是简单的循环胜出。那么parametrizedStream的效率就值得怀疑了。
- //是否因为没有正确设置并行度,还是计算机的环境存在问题
- test1000.sumByGiver();
- test1000.count();
- }
- }
复制代码 |