stream api 中 list to map and to list

学习stream api 记录一下笔记

public class StreamToMap {
	List<Student> list = Arrays.asList(new Student(1, 18, "阿才"),
            new Student(2, 18, "小强" ),
            new Student(3, 18, "啊星"));
		@Test
		public void listToMap(){
			  / /jdk1.8 lambda 表达式
			 Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, student->student));
			  // 遍历打印结果
				map.forEach((key, value) -> {
				System.out.println("key: " + key + "    value: " + value);
			});
		}
		
		@Test
		public void listToMapByName){
			// value 为对象中的属性
			Map<Integer, String> map = list.stream().collect(Collectors.toMap(Student::getId, Student::getName));
			map.forEach((key, value) -> {
			System.out.println("key: " + key + "    value: " + value);
		});
       }
		
		@Test
		public void listToListByName(){
			// value 为对象中的属性
			List< String> list1 = list.stream().map(e -> e.getName()).collect(Collectors.toList());
			list1.forEach((value) -> {
			  System.out.println( "value: " + value);
		});
       }
		
		@Test
		public void listToList(){  
			List<String> wordList = new ArrayList<>();
			wordList.add("a");
			wordList.add("b");
			wordList.add("c");
			// value 为对象中的属性
			List<String> output = wordList.stream().
					map(String::toUpperCase).
					collect(Collectors.toList());		
			output.forEach((value)-> System.out.println(value));
       }
		
		@Test
		public void filtList() {
			Integer[] sixNums = {1, 2, 3, 4, 5, 6};
			Integer[] evens =
			Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);  //过滤操作
			System.out.println(evens[0]);
		}

}	
		
		
class Student{	
	Integer id;
	Integer age;
	String name;	
	public Student(Integer id, Integer age, String name) {
		super();
		this.id = id;
		this.age = age;
		this.name = name;
	}
		public Integer getId() {
			return id;
		}
		public void setId(Integer id) {
			this.id = id;
		}
		public Integer getAge() {
			return age;
		}
		public void setAge(Integer age) {
			this.age = age;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		
	
}
<think> 我们被要求使用Stream APIList转换为Map。根据引用[2]和引用[3],我们可以使用`Collectors.toMap`或`Collectors.groupingBy`来实现。 主要两种转换方式: 1. 使用`Collectors.toMap`:将每个元素映射为键值对,适合一对一的映射(即每个键对应一个值)。 2. 使用`Collectors.groupingBy`:将元素按某个属性分组,适合一对多的映射(即每个键对应一个列表的值)。 下面分别详细说明: 方法一:使用`Collectors.toMap`(键唯一) 如果List中的元素转换为Map时,键是唯一的,那么可以使用`toMap`。如果键有重复,则会抛出`IllegalStateException`异常,除非我们提供合并函数(merge function)来解决冲突。 基本语法: ```java Map<K, V> map = list.stream() .collect(Collectors.toMap( keyMapper, // 函数:从元素中提取键 valueMapper, // 函数:从元素中提取值 mergeFunction // 可选:当键冲突时,如何合并两个值(例如,如果两个元素有相同的键,则可以选择保留其中一个或合并) )); ``` 示例1:将对象列表转换为以对象某个属性为键,对象本身为值的Map(假设键唯一) ```java List<Person> personList = ...; // 假设Person类有id和name Map<Long, Person> personMap = personList.stream() .collect(Collectors.toMap( Person::getId, // 键:Person对象的id person -> person // 值:对象本身 )); ``` 示例2:如果键可能重复,我们可以指定合并规则(例如,保留先出现的,或后出现的,或合并) ```java // 假设有两个Person对象可能有相同的id,我们想要保留后出现的 Map<Long, Person> personMap = personList.stream() .collect(Collectors.toMap( Person::getId, person -> person, (existing, replacement) -> replacement // 当有重复键时,用新值替换旧值 )); ``` 方法二:使用`Collectors.groupingBy`(键可以重复,一个键对应多个值) 如果我们希望将相同键的元素收集到一个列表中,那么应该使用`groupingBy`。 基本语法: ```java Map<K, List<V>> map = list.stream() .collect(Collectors.groupingBy( keyMapper, // 提取键 Collectors.mapping(valueMapper, Collectors.toList()) // 可选:对每个分组中的元素进行映射并收集为列表 )); ``` 实际上,如果直接使用`groupingBy`只指定键提取函数,那么值默认就是该元素本身,并且收集到一个列表中。 示例3:将相同城市的Person对象分组(键为城市,值为该城市的Person列表) ```java Map<String, List<Person>> peopleByCity = personList.stream() .collect(Collectors.groupingBy(Person::getCity)); ``` 示例4:如果我们想要分组后对元素进行进一步转换(例如,只取名字而不是整个对象) ```java Map<String, List<String>> cityToNames = personList.stream() .collect(Collectors.groupingBy( Person::getCity, Collectors.mapping(Person::getName, Collectors.toList()) )); ``` 引用[2]中展示了使用`groupingBy`将List转换为`Map<String, List<Region>>`,即按父代码分组。 引用[3]中展示了使用`toMap`将List转换为`Map<String, ProjectLineAreaVo>`,其中键由两个属性拼接而成。 注意事项: 1. 使用`toMap`时,如果键重复且没有指定合并函数,会抛出异常。 2. 使用`groupingBy`时,即使键重复也不会抛出异常,而是将相同键的元素收集到列表中。 3. 如果使用`toMap`并且希望值为列表(即一对多),那么不能直接使用`toMap`,而应该使用`groupingBy`。 因此,根据需求选择合适的方法: - 一对一(键唯一):`toMap` - 一对多(键重复,需要分组):`groupingBy` 另外,引用[3]中还有将List中元素的某个属性收集为List的例子: ```java List<Long> idList = list.stream().map(BasSpacePackage::getId).collect(Collectors.toList()); ``` 但这不是转换为Map,而是转换为List。 总结: 使用Stream APIList转换为Map有两种主要方式: 1. 使用`Collectors.toMap`:适合将每个元素转换为唯一的键值对。 2. 使用`Collectors.groupingBy`:适合将元素按键分组,形成键到列表的映射。 根据具体需求选择方法,并注意处理键重复的情况(在`toMap`中必须提供合并函数)。 下面我们给出几个常见的转换示例: 示例5:将List转换为Map,其中键是id,值是name(假设id唯一) ```java Map<Long, String> idToNameMap = personList.stream() .collect(Collectors.toMap( Person::getId, Person::getName )); ``` 示例6:将List转换为Map,其中键是城市,值是该城市的所有Person的年龄列表 ```java Map<String, List<Integer>> cityToAges = personList.stream() .collect(Collectors.groupingBy( Person::getCity, Collectors.mapping(Person::getAge, Collectors.toList()) )); ``` 示例7:如果键可能重复,且我们想用`toMap`并取第一个值(忽略后面的重复键) ```java Map<Long, Person> firstPersonMap = personList.stream() .collect(Collectors.toMap( Person::getId, person -> person, (first, second) -> first // 遇到重复id时,保留第一个 )); ``` 示例8:使用`groupingBy`并指定下游收集器为计数(统计每个城市的数量) ```java Map<String, Long> countByCity = personList.stream() .collect(Collectors.groupingBy( Person::getCity, Collectors.counting() )); ``` 希望这些示例能帮助您理解如何使用Stream APIList转换为Map。 </think> 在 Java Stream API 中将 `List` 转换为 `Map` 主要有两种核心方式,分别使用 `Collectors.toMap()` 和 `Collectors.groupingBy()`。以下是详细方法和示例: --- ### 一、使用 `Collectors.toMap()`(一对一映射) #### 1. **基础转换(键唯一)** ```java List<Person> personList = Arrays.asList( new Person(1, "Alice"), new Person(2, "Bob") ); // 键:id,值:name Map<Integer, String> idToNameMap = personList.stream() .collect(Collectors.toMap( Person::getId, // 键提取函数 Person::getName // 值提取函数 )); // 结果:{1="Alice", 2="Bob"} ``` #### 2. **处理键冲突(重复键合并)** ```java List<Person> duplicateList = Arrays.asList( new Person(1, "Alice"), new Person(1, "Alex") // 相同ID ); // 合并策略:保留后出现的值 Map<Integer, String> mergedMap = duplicateList.stream() .collect(Collectors.toMap( Person::getId, Person::getName, (oldVal, newVal) -> newVal // 冲突处理函数 )); // 结果:{1="Alex"} ``` #### 3. **键为复合值** ```java Map<String, Person> compositeKeyMap = personList.stream() .collect(Collectors.toMap( p -> p.getId() + "_" + p.getName(), // 复合键 p -> p, // 值=对象本身 (oldVal, newVal) -> newVal // 冲突处理 )); // 结果:{"1_Alice": Person@123, "2_Bob": Person@456} ``` --- ### 二、使用 `Collectors.groupingBy()`(一对多分组) #### 1. **基础分组** ```java List<Person> groupList = Arrays.asList( new Person(1, "Alice", "Tech"), new Person(2, "Bob", "Tech"), new Person(3, "Charlie", "HR") ); // 按部门分组 Map<String, List<Person>> deptMap = groupList.stream() .collect(Collectors.groupingBy(Person::getDepartment)); /* 结果: { "Tech": [Person(1,"Alice"), Person(2,"Bob")], "HR": [Person(3,"Charlie")] } */ ``` #### 2. **分组后值转换** ```java // 按部门分组,值提取为名称列表 Map<String, List<String>> deptToNames = groupList.stream() .collect(Collectors.groupingBy( Person::getDepartment, Collectors.mapping(Person::getName, Collectors.toList()) )); // 结果:{"Tech": ["Alice","Bob"], "HR": ["Charlie"]} ``` #### 3. **分组统计** ```java // 按部门统计人数 Map<String, Long> deptCount = groupList.stream() .collect(Collectors.groupingBy( Person::getDepartment, Collectors.counting() )); // 结果:{"Tech":2, "HR":1} ``` --- ### 三、注意事项 1. **键唯一性问题** - 使用 `toMap()` 时需确保键唯一,否则需提供合并函数(如示例2)。 - 使用 `groupingBy()` 时自动处理重复键(值转为集合)。 2. **空指针处理** 若键可能为 `null`,需提前过滤: ```java Map<Integer, String> safeMap = personList.stream() .filter(p -> p.getId() != null) .collect(Collectors.toMap(...)); ``` 3. **自定义Map实现** 指定具体 `Map` 实现类: ```java Map<Integer, Person> linkedMap = personList.stream() .collect(Collectors.toMap( Person::getId, p -> p, (oldVal, newVal) -> newVal, LinkedHashMap::new // 保持插入顺序 )); ``` --- ### 四、方法对比 | 场景 | 推荐方法 | 示例 | |--------------------------|------------------------|---------------------------| | 键值一对一(键唯一) | `Collectors.toMap()` | 用户ID → 用户名 | | 键值一对多(分组) | `Collectors.groupingBy()` | 部门 → 员工列表 | | 键冲突需合并 | `toMap()` + 合并函数 | 相同ID取最新值 | | 分组后聚合操作 | `groupingBy()` + 下游收集器 | 统计部门人数 | > 📌 **最佳实践**: > - 键唯一时优先用 `toMap()`(更简洁)[^2] > - 分组统计用 `groupingBy()` + `mapping()`/`counting()`[^3] > - 复合键用 Lambda 表达式拼接(如 `k1 + "_" + k2`)[^3] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值