Java 集合框架(List, Set, Map)练习题

核心收获:熟练掌握 Java 集合框架(List, Set, Map)

‌练习1 --- List 去重与保留顺序‌

移除列表中的重复元素并保持首次出现的顺序,使用 LinkedHashSet 构造函数或 Stream 的 distinct(),对比 HashSet 丢失顺序的场景。

java 复制代码
//练习1:List去重与保留顺序
        //测试数据
        List<String> duplicateList = Arrays.asList("A", "B", "A", "C", "B", "D", "E", "T", "G", "F", "Y", "G");
        //方法1:使用LinkedHashSet(底层基于插入顺序的哈希表,天然保序)
        List<String> distinctWithOrderOne = new ArrayList<>(new LinkedHashSet<>(duplicateList));
        System.out.println("LinkedHashSet去重保序结果:" + distinctWithOrderOne);
        //方法2:使用Stream.distinct()(底层基于LinkedHashSet实现,同样保序)
        List<String> distinctWithOrderTwo = duplicateList.stream().distinct().collect(Collectors.toList());
        System.out.println("Stream.distinct()去重保序结果:" + distinctWithOrderTwo);
        //方法3:对比:普通HashSet会丢失插入顺序
        List<String> distinctNoOrder = new ArrayList<>(new HashSet<>(duplicateList));
        System.out.println("HashSet去重丢失顺序结果:" + distinctNoOrder);

        //输出结果:
        //LinkedHashSet去重保序结果:[A, B, C, D, E, T, G, F, Y]
        //Stream.distinct()去重保序结果:[A, B, C, D, E, T, G, F, Y]
        //HashSet去重丢失顺序结果:[A, B, C, D, E, F, G, T, Y]

‌练习2 --- Map 安全获取与默认值‌

从 Map 中获取用户配置,若 Key 不存在则返回默认配置对象,使用 Map.getOrDefault() 或 computeIfAbsent() 避免空指针异常(NPE)。

java 复制代码
        //练习2:Map的安全获取与默认值
        //测试数据
        Map<String, String> userConfig = new HashMap<>();
        userConfig.put("theme", "dark");
        userConfig.put("fontSize", "16");
        //方法1:getOrDefault,仅查询不写入Map
        String theme = userConfig.getOrDefault("theme", "light");
        String unknownKey = userConfig.getOrDefault("unknownKey", "defaultValue");
        System.out.println("theme配置:" + theme);
        System.out.println("不存在的key默认值:" + unknownKey);
        //方法2:computeIfAbsent,若key不存在则写入默认值到Map,后续直接复用
        String cacheConfig = userConfig.computeIfAbsent("cacheExpire", k -> "3600");
        System.out.println("新增的缓存配置:" + cacheConfig);
        System.out.println("Map最终内容:" + userConfig);
        //输出结果:
        //theme配置:dark
        //不存在的key默认值:defaultValue
        //新增的缓存配置:3600
        //Map最终内容:{cacheExpire=3600, theme=dark, fontSize=16}

‌练习3 --- 集合求交集与差集‌

找出两个用户标签列表(List)的共同标签(交集)和独有标签(差集),使用 retainAll() / removeAll() 或 Stream 的 filter + contains,注意大数据量下的性能优化(转为 HashSet 查找)。

java 复制代码
       //练习3集合求交集与差集
        //测试数据
        List<String> tagsOne = new ArrayList<>(Arrays.asList("Java", "Spring", "AI", "MySQL"));
        List<String> tagsTwo = new ArrayList<>(Arrays.asList("Spring", "Redis", "Java", "Kafka"));
        //性能优化:先转HashSet,将contains操作从O(n)降为O(1),适配大数据量场景
        Set<String> tagSetOne = new HashSet<>(tagsOne);
        Set<String> tagSetTwo = new HashSet<>(tagsTwo);

        //1:求交集(共同标签)
        Set<String> intersection = new HashSet<>(tagSetOne);
        intersection.retainAll(tagSetTwo);
        System.out.println("共同标签:" + intersection);

        //2:求差集(tagOne独有的标签)
        Set<String> difference = new HashSet<>(tagSetOne);
        difference.removeAll(tagSetTwo);
        System.out.println("tagOne独有的标签:" + difference);

        //3:Stream写法实现交集
        List<String> streamIntersection = tagsOne.stream().filter(tagSetTwo::contains).collect(Collectors.toList());
        System.out.println("Stream实现交集:" + streamIntersection);

        //4:Stream写法实现差集
        List<String> streamDifference = tagsOne.stream().filter(tag -> !tagSetTwo.contains(tag)).collect(Collectors.toList());
        System.out.println("Stream实现差集:" + streamDifference);

        //输出结果
        //共同标签:[Java, Spring]
        //tagOne独有的标签:[MySQL, AI]
        //Stream实现交集:[Java, Spring]
        //Stream实现差集:[AI, MySQL]

‌练习4 --- List 转 Map 分组与映射‌

将订单列表按"状态"分组统计总金额,使用 Collectors.groupingBy 嵌套 Collectors.summingDouble;或将列表直接转为 Map<ID, Object> 以便快速查找,使用 Collectors.toMap 并处理键冲突策略。

java 复制代码
       //练习4:List转Map分组与映射
        //测试数据
        List<Order> orders = Arrays.asList(new Order(1L, 1, 99.9),
                new Order(2L, 1, 199.9),
                new Order(3L, 2, 299.9),
                new Order(4L, 2, 399.9));
        //1:按订单状态分组,统计每个状态的总金额
        Map<Integer, Double> statusTotalMap = orders.stream().collect(Collectors.groupingBy(Order::status, Collectors.summingDouble(Order::amount)));
        System.out.println("按订单状态分组总金额:" + statusTotalMap);

        //2:转成ID-订单的快速查找Map,处理键冲突
        Map<Long, Order> idToOrderMap = orders.stream().collect(Collectors.toMap(Order::id, order -> order, (oldVal, newVal) -> oldVal));
        System.out.println("ID映射订单Map:" + idToOrderMap);

        //输出结果:
        //按订单状态分组总金额:{1=299.8, 2=699.8}
        //ID映射订单Map:{1=Order[id=1, status=1, amount=99.9],
        // 2=Order[id=2, status=1, amount=199.9],
        // 3=Order[id=3, status=2, amount=299.9],
        // 4=Order[id=4, status=2, amount=399.9]}