假设需求时这样的
将一个对象list转换成map
// 原数据:
List<Order> orders;
// 转换后数据:
Map<Long, String> orderMaps;
list里的元素
转换后map的key-value
现阶段的解决方式一般有2大类
- java代码里显示使用for循环
- 通过stream的内循环
先写简单的方案,显示for循环如下
// 我不写了,这个太简单了
再来写stream的方案
- 通过集合类型的.stream()函数将集合转成流,
- 然后通过collect()函数收集流数据,
- 此函数的参数是Collectors.toXXX();
代码如下:
准备工作1,这是模拟的订单类,凑合一下
/**
* 模拟订单类
*/
@Data
@AllArgsConstructor
@Accessors(chain = true)
class Order {
private Long id;
private String receiverName;
}
准备工作2,准备一个订单集合
static List<Order> buildOrders() {
Order order1 = new Order(1L, "李静");
Order order2 = new Order(2L, "沙坪");
Order order3 = new Order(3L, "老李");
List<Order> orders = new ArrayList<>(3);
orders.add(order1);
orders.add(order2);
orders.add(order3);
return orders;
}
处理工作,将list转成map
先来写个简易版本
// 方式1, 简易版
Map<Long, String> map2 = orders.stream().collect(Collectors.toMap(
kv -> { // 处理key的函数
return kv.getId();
},
kv -> { // 处理value的函数
return kv.getReceiverName();
}));
// 观察返回map的类型
System.out.println(map2.getClass());
map2.forEach((k, v) -> {
System.out.println(k + "-" + v);
});
执行结果如下:可以发现返回map的类型是java.util.HashMap
class java.util.HashMap
1-李静
2-沙坪
3-老李
再来写一个进阶版本,这是看阿里开发手册发现的
因为原集合转换成map的过程中,有可能会出现key重复,为了解决key重复,所以Collectors.toMap函数提供了重载方法,第三个参数函数用于处理key重复
方式2,进阶版
Map<Long, String> map3 = orders.stream().collect(Collectors.toMap(
kv -> {
return kv.getId();
},
kv -> {
return kv.getReceiverName();
},
(oldKey, newKey) -> { // 处理key重复的函数
System.err.println("key重复,已替换");
return newKey;
}));
System.out.println(map3.getClass());
map3.forEach((k, v) -> {
System.out.println(k + "-" + v);
});
执行之前做下修改:
这里需要先将原集合,即order集合里的元素值改成如下内容,order2与order3的id都是2L,这样会出现key重复
Order order1 = new Order(1L, "李静");
Order order2 = new Order(2L, "沙坪");
Order order3 = new Order(2L, "老李");
执行结果如下:
- 简易版的执行结果:很显然的报出了key重复的异常
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 沙坪
at java.util.stream.Collectors.lambda0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda58(Collectors.java:1320)
at java.util.stream.ReduceOpsArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.enn.sale.crm.clue.web.Test.main(Test.java:39)
- 进阶版本执行结果:没啥问题,重复的key已经按照代码内容处理了,返回map类型依然是java.util.HashMap
class java.util.HashMap
1-李静
2-老李
再写一个增强版本吧
这个版本的目的是,指定转换后map类型,比如我不想用HashMap,我可以指定为TreeMap
Map<Long, String> map4 = orders.stream().collect(Collectors.toMap(
kv -> {
return kv.getId();
},
kv -> {
return kv.getReceiverName();
},
(oldKey, newKey) -> {
System.err.println("key重复,已替换");
return newKey;
},
() -> {
// 此处是个提供者类型的函数式接口,不用参数,只返回
// 返回值为指定转换后map的类型的对象
// 源码注释是这样的,自己体会吧
// a function which returns a new, empty {@code Map} into
// * which the results will be inserted
return new TreeMap<>();
}
));
System.out.println(map4.getClass());
map4.forEach((k, v) -> {
System.out.println(k + "-" + v);
});
执行结果如下:返回类型已经是java.util.TreeMap
class java.util.TreeMap
1-李静
2-老李
本篇内容基本上写完了,建议在开发中尽量不要使用简易版本,key重复这种情况很难避免
粘贴下1.8的部分源码
/**
* @param keyMapper a mapping function to produce keys
* @param valueMapper a mapping function to produce values
* @param mergeFunction a merge function, used to resolve collisions between
* values associated with the same key, as supplied
* to {@link Map#merge(Object, Object, BiFunction)}
* @param mapSupplier a function which returns a new, empty {@code Map} into
* which the results will be inserted
* @return a {@code Collector} which collects elements into a {@code Map}
* whose keys are the result of applying a key mapping function to the input
* elements, and whose values are the result of applying a value mapping
* function to all input elements equal to the key and combining them
* using the merge function
*
* @see #toMap(Function, Function)
* @see #toMap(Function, Function, BinaryOperator)
* @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
*/
public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
写完收工