当前位置: 首页 > article >正文

Map集合

1. 键不能重复

如果 keyMapper 生成的键重复,会抛出 IllegalStateException 异常。

定义: Map 是一个独立于 Collection 的接口,用于存储键值对(key-value pair),即双列集合。

实现类:

HashMap: 无序存储。

TreeMap: 键按自然顺序或自定义排序存储。

LinkedHashMap: 按插入顺序存储。

特点: 每个元素是一个键值对,例如 {"key1": "value1", "key2": "value2"}

键(key)必须唯一。

值(value)可以重复。

Map集合的遍历方式:

1. 通过键(Key)集合遍历

  • 使用 keySet() 方法获取所有键的集合,然后通过遍历键获取对应的值。
  • 适用场景: 需要遍历所有键及其对应的值时。
Map<String, String> map = new HashMap<>();
map.put("name", "Alice");
map.put("age", "25");
map.put("city", "New York");

for (String key : map.keySet()) {
    System.out.println("Key: " + key + ", Value: " + map.get(key));
}

2. 通过键值对(Entry)遍历

  • 使用 entrySet() 方法获取所有键值对的集合,然后通过遍历每个键值对获取键和值。
  • 优点: 性能比键集合遍历方式更高,因为直接获取了键值对,无需通过键再查询值。
  • 适用场景: 需要同时操作键和值时。
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

3. 通过值(Value)集合遍历

  • 使用 values() 方法获取所有值的集合,然后直接遍历值。
  • 适用场景: 仅需要操作所有值时。
for (String value : map.values()) {
    System.out.println("Value: " + value);
}

4. 通过Lambada表达式 

使用 forEach 方法:

Map<String, String> map = new HashMap<>();
map.put("name", "Alice");
map.put("age", "25");
map.put("city", "New York");

map.forEach((key, value) -> {
    System.out.println("Key: " + key + ", Value: " + value);
});

为什么直接写 key, value 是允许的?

流程总结

  • entrySet()Map 转化为一个键值对集合。
  • for 循环从 entrySet 中逐一取出 Map.Entry
  • entry.getKey()entry.getValue() 作为参数,调用 BiConsumeraccept 方法。
  • 你的 Lambda 表达式 (key, value) -> {...} 就是 BiConsumer 接口的具体实现。

HashMap

1. 默认初始化

  • 数组长度: HashMap 初始化时,会创建一个默认长度为 16 的数组,数组的每个位置被称为“桶”。
  • 加载因子: 默认加载因子为 0.75,即当 HashMap 中的元素数量超过 capacity * loadFactor 时(例如,16 × 0.75 = 12),就会触发扩容操作,扩容为原来容量的两倍(即 32)。

2. 添加元素的 put 方法

put 方法是 HashMap 添加键值对的入口,其主要逻辑如下:

2.1 创建 Node 对象
  • NodeHashMap 中的内部类,用于存储键值对。

每个 Node 包括:hash: 哈希值,用于快速定位数组索引。key: 键。value: 值。

2.2 计算哈希值

HashMap 使用键的 hashCode 方法计算哈希值

2.3 计算数组索引

利用哈希值与数组长度计算元素存储的位置

2.4 判断冲突
  • 如果该位置为空:
    • 直接将 Node 存入对应位置。
  • 如果该位置不为空(冲突):
    • 遍历链表或树:
      • 键相等(equals 方法比较): 覆盖旧值。
      • 键不相等: 将新 Node 挂在链表末尾。

插入操作

  • 插入的键值对被包装成 Node 对象。
  • 通过哈希值找到对应的数组索引。
  • 如果索引位置为空,直接存储。
  • 如果发生哈希冲突(同一个索引处已有其他节点),则采用以下方式:
    1. 遍历链表检查是否存在相同键(覆盖旧值)。
    2. 如果链表长度超过 8 且数组长度 ≥ 64,将链表转为红黑树存储。
    3. 如果链表长度小于等于 8,仍以链表存储。

总结:

首先在底层,会创建一个长度为16,默认加载因子为0.75的数组。使用put方法就可以添加元素了。添加元素时,put会创建一个Entry对象,里面储存键和值,利用键计算出哈希值,跟值无关。在计算出在数组中应该存入的索引。如果该位置为null,直接添加到数组当中,如果不为null,会调用equals方法比较键,如果键相同,那么就会覆盖。如果键不相同,就会挂在旧的元素下方形成一个链表。当数组长度>=64且链表长度>=8 的时候,就会自动转换为红黑树提高效率 

 LinkedHashMap

TreeMap

默认就是按照键的升序进行排列 

可变参数 

Java 中,可变参数(Varargs)是 Java 5 引入的一个功能,通过使用省略号 ... 表示,它允许方法接收可变数量的参数。以下是详细的讲解。

package varibleChange;
// 注意可变参数在一个方法当中只能写一个可变参数
// 可变参数只能写在所有参数的最后面
// 底层相是数组,相当于java帮我们创建了一个数组,这样我们就不需要手动创建了
public class base {
    public static void main(String[] args) {
        System.out.println(getSum(1,2,3,4,5,6,7,8,9,10));
    }
    public static int getSum(int ...arr){
        int sum = 0;
        for (int i : arr) {
            sum += i;
        }
        return sum;
    }
}

 一定要注意:

如果一个方法既有普通参数,又有可变参数,可变参数必须是最后一个。并且只能有一个可变参数

 可变参数我感觉这里就行python的*一样,一个大胖子,把传过来的参数全部吸收

 不可变集合

Stream流

注意:Stream接口中静态方法of的细节方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到stream当中。

中间方法 

注意1:中间方法,返回新的stream流,原来的stream流只能使用一次,建议使用链式编程

注意2:修改stream流中的数据,不会影响原来集合或者数组中的数据 

重点来讲下map方法 :

map 方法的主要作用是对流中的每个元素进行转换,通过一个指定的函数,将原始数据映射为新的数据。

如何使用map方法将字符串转换为Actor(自定义)对象?

其实就是使用自定义对象的有参构造方法来构造出一个自定义对象,储存数据

ArrayList<String> manAct = new ArrayList<>();
Collections.addAll(manAct, "张三大,18", "王五,25", "赵六,21", "孙七,22", "李华,22", "小李子,23");

ArrayList<String> femaleAct = new ArrayList<>();
Collections.addAll(femaleAct, "李四,19", "格格,21", "杨天安,22", "玉玉,23", "杨宝贝,26", "赵八,19");

// 男演员:名字为3个字的前两个人
List<String> filteredManAct = manAct.stream()
                                    .filter(s -> s.split(",")[0].length() == 3)
                                    .limit(2)
                                    .collect(Collectors.toList());

// 女演员:名字包含“杨”,但跳过第一个
List<String> filteredFemaleAct = femaleAct.stream()
                                          .filter(s -> s.split(",")[0].contains("杨"))
                                          .skip(1)
                                          .collect(Collectors.toList());

// 合并两个流,并将字符串转换为 Actor 对象
List<Actor> actors = Stream.concat(filteredManAct.stream(), filteredFemaleAct.stream())
                           .map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])))
                           .collect(Collectors.toList());

// 输出结果
actors.forEach(System.out::println);

其中map方法详细一点就是:

.map(info -> {
    String[] parts = info.split(",");
    String name = parts[0];
    int age = Integer.parseInt(parts[1]);
    return new Actor(name, age);
})
终结方法 

重点来说下转换为map集合,需要注意的是我们将流收集成map集合的时候,需要指定key和value的值 

import java.util.*;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("张三,18", "李四,25", "王五,30");

        // 将流收集为 Map,键是姓名,值是年龄
        Map<String, Integer> map = data.stream()
            .collect(Collectors.toMap(
                // keyMapper: 提取名字
                s -> s.split(",")[0],
                // valueMapper: 提取年龄并转换为整数
                s -> Integer.parseInt(s.split(",")[1])
            ));

        System.out.println(map);
        // 输出: {张三=18, 李四=25, 王五=30}
    }
}

键不能重复

如果 keyMapper 生成的键重复,会抛出 IllegalStateException 异常。

        // 将流转换为数组
        Integer[] age = list2.stream().map(s -> Integer.parseInt(s.split("-")[1])).toArray(value -> new Integer[value]);
        for (Integer integer : age) {
            System.out.println(integer);
        }
        // 筛选出性别为男的,并且转换为集合
        List<String> collect = list2.stream().filter(s -> s.contains("男")).collect(Collectors.toList());
        collect.forEach(System.out::println);

        // 转换为map,需要指定键和值
        Map<String, Integer> map = list2.stream().filter(s -> s.contains("男")).collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[1])));
        System.out.println(map);


http://www.kler.cn/a/470342.html

相关文章:

  • 三极管工作状态分析
  • 数字IC设计高频面试题
  • 【C++】线程启动、结束与创建线程写法
  • tcpdump-命令详解
  • 彻底学会Gradle插件版本和Gradle版本及对应关系
  • 数学建模入门——描述性统计分析
  • QT6编程入门(一)
  • 每日一题:BM2 链表内指定区间反转
  • 分布式搜索引擎之elasticsearch基本使用3
  • 电脑如何无线控制手机?
  • VVenC 编码器源码结构与接口函数介绍
  • 复古柯达胶片电影效果肖像风景街头摄影Lightroom调色预设 Koda Film Preset Pack | Cinematic Presets
  • Django 模型
  • 20250106面试
  • R语言的计算机基础
  • HTML 显示器纯色亮点检测工具
  • Chapter4.1 Coding an LLM architecture
  • CentOS Stream 9上安装配置NFS
  • HarmonyOS UIAbility 生命周期与窗口管理实践
  • C/C++:按照C的顺序,看汇编语言程序是乱序
  • Linux(17)——使用 DNF 安装和更新软件包
  • 25年01月HarmonyOS应用基础认证最新题库
  • 最新最详细的配置Node.js环境教程
  • 在Java中使用有符号类型模拟无符号整数的技巧
  • iOS - 原子操作
  • 使用EasyRec优化搜索广告推荐深度学习排序模型的性能