Java流列表转换为映射(Map)

时间:2020-02-23 14:35:11  来源:igfitidea点击:

在本教程中,我们将看到如何使用Java 8中的Stream转换为映射。

Collector toMap()可以与流一起使用以将列表转换为Java中的映射。

考虑一个名字的程序 Movie有3个字段 idnamegenre

package org.igi.theitroad;
 
public class Movie {
 
	private String name;
	private String genre;
 
	public Movie(String name, String genre) {
		super();
		this.name = name;
		this.genre = genre;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public String getGenre() {
		return genre;
	}
 
	public void setGenre(String genre) {
		this.genre = genre;
	}
 
	@Override
	public String toString() {
		return "Movie [name=" + name + ", genre=" + genre + "]";
	}
}

创建电影列表并使用映射转换为 name作为关键 genre作为值。

创建一个名为的类 ConvertListToMapMain

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
 
public class ConvertListToMapMain {
 
	public static void main(String[] args) {
		List<Movie> moviesList=getListOfMovies();
		
		Map<String, String> moviesMap = moviesList.stream()
		          .collect(Collectors.toMap((m)->m.getName(), (m)->m.getGenre()));
		System.out.println(moviesMap);
	}  
	
	public static List<Movie> getListOfMovies()
	{
		List<Movie> moviesList=new ArrayList<>();
		
		Movie m1=new Movie("3 idiots","Comedy");
		Movie m2=new Movie("Interstellar","SciFi");
		Movie m3=new Movie("Forest gump","Comedy");
		Movie m4=new Movie("Matrix","SciFi");
		Movie m5=new Movie("The Hangover","Comedy");
		
		moviesList.add(m1);
		moviesList.add(m2);
		moviesList.add(m3);
		moviesList.add(m4);
		moviesList.add(m5);
		
		return moviesList;
	}
}

输出:

{Interstellar=SciFi, Matrix=SciFi, The Hangover=Comedy, Forest gump=Comedy, 3 idiots=Comedy}

moviesMap包含名称为键和类型为值。
我们还可以使用方法引用而不是LAMDA表达式。

Map<String, String> moviesMap = moviesList.stream()
		          .collect(Collectors.toMap(Movie::getName, Movie::getGenre()));

在重复密钥的情况下会发生什么?

如果存在重复的键,则会抛出重复键 java.lang.IllegalStateException例外。

假设我们有两个名称的电影 Matrix

public static List<Movie> getListOfMovies()
	{
		List<Movie> moviesList=new ArrayList<>();
		
		Movie m1=new Movie("3 idiots","Comedy");
		Movie m2=new Movie("Interstellar","SciFi");
		Movie m3=new Movie("Forest gump","Comedy");
		Movie m4=new Movie("Matrix","SciFi");
		Movie m5=new Movie("Matrix","Comedy");
		
		moviesList.add(m1);
		moviesList.add(m2);
		moviesList.add(m3);
		moviesList.add(m4);
		moviesList.add(m5);
		
		return moviesList;
	}

当我们再次运行ConvertListtomapMain时,我们将得到以下输出:

Exception in thread “main" java.lang.IllegalStateException: Duplicate key Sci Fi at java.util.stream.Collectors.lambda$throwingMerger
Map<String, String> moviesMap = moviesList.stream()
		.collect(Collectors.toMap((m)->m.getName(), (m)->m.getGenre(),
		        (oldValue,newValue) -> newValue
		));
(Collectors.java:133) at java.util.HashMap.merge(HashMap.java:1254) at java.util.stream.Collectors.lambda$toMap(Collectors.java:1320) at java.util.stream.ReduceOpsReducingSink.accept(ReduceOps.java:169) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) 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:566) at org.arpit.theitroad.ConvertListToMapMain.main(ConvertListToMapMain.java:14)

要解决此问题,我们需要通过合并 BinaryOperator函数 Collectors.toMap()

Map<String, String> moviesMap = moviesList.stream()
		          .collect(Collectors.toMap( (m)->m.getName(), (m)->m.getGenre(),
		        		  (oldValue,newValue) -> newValue
		        		  ,TreeMap::new
		        		  ));

如果我们想要特定映射(Map),如Treemap,该怎么办?

我们可以通过构造方法参考

Collectors.toMap()获取特定映射(Map)。

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
 
public class ConvertListToMapMain {
 
	public static void main(String[] args) {
		List<Movie> moviesList=getListOfMovies();
		
		Map<String, List<String>> moviesGenMap = moviesList.stream()
		          .collect(Collectors.groupingBy(Movie::getGenre
		        		                        ,Collectors.mapping(Movie::getName, Collectors.toList())));
		System.out.println(moviesGenMap);
	}  
	
	public static List<Movie> getListOfMovies()
	{
		List<Movie> moviesList=new ArrayList<>();
		
		Movie m1=new Movie("3 idiots","Comedy");
		Movie m2=new Movie("Interstellar","SciFi");
		Movie m3=new Movie("Forest gump","Comedy");
		Movie m4=new Movie("Matrix","SciFi");
		Movie m5=new Movie("The Hangover","Comedy");
		
		moviesList.add(m1);
		moviesList.add(m2);
		moviesList.add(m3);
		moviesList.add(m4);
		moviesList.add(m5);
		
		return moviesList;
	}
 
}

当我们再次运行ConvertListtomapMain时,我们将得到以下输出

正如你所看到的,我们有 TreeMap按名称排序。

使用收集器获取Multimap.groupBy()

如果,我们希望受欢迎作为键和名称分组的电影为键,那么我们可以使用Colormors.GroupingBy()和收集器。

映射如下:

##代码##

moviesGenMap将流派作为键和电影名称作为价值的键。