list的转map的另一种猜想
Java8使用lambda表达式进行函数式编程可以对集合进行非常方便的操作。一个比较常见的操作是将list转换成map,一般使用Collectors的toMap()方法进行转换。一个比较常见的问题是当list中含有相同元素的时候,如果不指定取哪一个,则会抛出异常。因此,这个指定是必须的。
当然,使用toMap()的另一个重载方法,可以直接指定。这里,我们想讨论的是另一种方法:在进行转map的操作之前,能不能使用distinct()先把list的重复元素过滤掉,然后转map的时候就不用考虑重复元素的问题了。
使用distinct()给list去重
直接使用distinct(),失败
package example.mystream;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ListToMap {
@AllArgsConstructor
@NoArgsConstructor
@ToString
private static class VideoInfo {
@Getter
String id;
int width;
int height;
}
public static void main(String [] args) {
List<VideoInfo> list = Arrays.asList(new VideoInfo("123", 1, 2),
new VideoInfo("456", 4, 5), new VideoInfo("123", 1, 2));
// preferred: handle duplicated data when toMap()
Map<String, VideoInfo> id2VideoInfo = list.stream().collect(
Collectors.toMap(VideoInfo::getId, x -> x,
(oldValue, newValue) -> newValue)
);
System.out.println("No Duplicated1: ");
id2VideoInfo.forEach((x, y) -> System.out.println("<" + x + ", " + y + ">"));
// handle duplicated data using distinct(), before toMap()
Map<String, VideoInfo> id2VideoInfo2 = list.stream().distinct().collect(
Collectors.toMap(VideoInfo::getId, x -> x)
);
System.out.println("No Duplicated2: ");
id2VideoInfo2.forEach((x, y) -> System.out.println("<" + x + ", " + y + ">"));
}
}
list里总共有三个元素,其中有两个我们认为是重复的。第一种转换是使用toMap()直接指定了对重复key的处理情况,因此可以正常转换成map。而第二种转换是想先对list进行去重,然后再转换成map,结果还是失败了,抛出了IllegalStateException,所以distinct()应该是失败了。
No Duplicated1:
<123, ListToMap.VideoInfo(id=123, width=1, height=2)>
<456, ListToMap.VideoInfo(id=456, width=4, height=5)>
Exception in thread "main" java.lang.IllegalStateException: Duplicate key ListToMap.VideoInfo(id=123, width=1, height=2)
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1253)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.stream.DistinctOps$1$2.accept(DistinctOps.java:175)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
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: