如何解决如何在使用 Collectors.groupby() 时迭代流中的对象
我有一个 bean 类 Hotel,其中数据成员为 HotelName
、HotelCity
、HotelContact
。
现在我想以一种方式将数据保存在 Hashmap 中,其中地图键应该是城市,并且所有酒店名称应该是属于城市的应该是地图值。我可以使用 Collectors.groupby()
做到这一点。但是,我无法获得 HotelName,而是获得了 Hotel
对象地址。请帮助我出错的地方。这是我尝试的代码:
class Hotel {
private String hotelName;
private String hotelCity;
private String hotelPhNo;
/*their getter setter methods*/
}
public static void main(String[] args) {
List<Hotel> ol = new ArrayList<Hotel>();
Hotel h1 = new Hotel("H1","Pune","123");
Hotel h2 = new Hotel("H2","Mumbai","109");
Hotel h3 = new Hotel("H3","1123");
Hotel h4 = new Hotel("H4","123");
Hotel h5 = new Hotel("H5","Ujjain","123");
Hotel h6 = new Hotel("H6","Indore","123");
Hotel h7 = new Hotel("H7","Sehore","123");
Hotel h8 = new Hotel("H8","123");
ol.add(h1);
ol.add(h2);
ol.add(h3);
ol.add(h4);
ol.add(h5);
ol.add(h6);
ol.add(h7);
ol.add(h8);
Map<String,List<Hotel>> res = ol.stream().collect(Collectors.groupingBy(Hotel:: getHotelCity));
res.forEach((a,b)->System.out.println("City:"+a+" with Hotels: "+b));
}
有了这个,我得到的输出如下:
City:Ujjain with Hotels: [Hotel@7ba4f24f]
City:Pune with Hotels: [Hotel@3b9a45b3,Hotel@7699a589,Hotel@58372a00]
City:Indore with Hotels: [Hotel@4dd8dc3]
City:Mumbai with Hotels: [Hotel@6d03e736,Hotel@568db2f2]
City:Sehore with Hotels: [Hotel@378bf509]
我想要的期望输出:
City:Ujjain with Hotels: [H5]
City:Pune with Hotels: [H1,H3,H8]
City:Indore with Hotels: [H6]
City:Mumbai with Hotels: [H4]
City:Sehore with Hotels: [H7]
请帮忙。我有一个要求,我不想通过覆盖 equals、hashcode 和 tostring 方法来更改 bean 类。覆盖这些方法会更简单地解决此问题,但会寻找替代方法。
解决方法
对于这样的输出,您需要 Map<String,List<String>>
数据结构。为此,请在 Collectors.mapping
中使用 Collectors.groupingBy
下游收集器。
Map<String,List<String>> res = ol.stream()
.collect(Collectors.groupingBy(Hotel:: getHotelCity,Collectors.mapping(Hotel::getHotelName,Collectors.toList())));
注意您需要提供额外的下游收集器 Collectors.toList()
,只要 Collectors.mapping
每次都需要它。
结果:
res.forEach((a,b)->System.out.println("City:"+a+" with Hotels: "+b));
City:Ujjain with Hotels: [H5]
City:Pune with Hotels: [H1,H3,H8]
City:Indore with Hotels: [H6]
City:Mumbai with Hotels: [H2,H4]
City:Sehore with Hotels: [H7]
如果你仍然想保持原来的 Map<String,List<Hotel>>
结构,但是以不同的方式打印出地图值,你需要改变打印结果的方式:
res.forEach((city,list) -> {
String hotels = list.stream()
.map(Hotel::getHotelName)
.collect(Collectors.joining(",","[","]"));
System.out.println("City:" + city + " with Hotels: " + hotels);
});
最后,几点说明:
-
用小写首字母命名类字段:
private String hotelName;
-
可以以更短的方式创建
List
:List<Hotel> ol = new ArrayList<>(Arrays.asList(h1,h2,h3,h4,h5,h6,h7,h8));
这里的问题是 b
代表 List<Hotel>
。要打印酒店名称,您应该使用 b
遍历列表 b.forEach(...)
,然后单独打印每个酒店信息。
您可以像这样更改打印语句:
res.forEach((a,b) -> {
System.out.println("City:" + a + " with Hotels: ");
b.forEach(h -> System.out.println("\t" + h.getHotelName()));
});
输出:
City:Ujjain with Hotels:
H5
City:Pune with Hotels:
H1
H3
H8
City:Indore with Hotels:
H6
City:Mumbai with Hotels:
H2
H4
City:Sehore with Hotels:
H7
,
您有 2 个选择。我认为选项 #2 在这里要优越得多。
-
不是以
Map<String /* City */,List<Hotel>>
结尾,而是以Map<String /* City */,List<String /* Name of hotel */>>
结尾。在您的流操作期间,使用下游映射器映射“值”部分:Collectors.mapping(Hotel::getHotelName,Collectors.toList())
。 -
保持数据结构完全相同,但让您的酒店在打印时打印有用的东西;它们目前呈现为
Hotel@7ba4f24f
,因为您的 Hotel 类缺少 toString 实现,这是一种糟糕的情况。要修复它,只需添加一个:向您的 Hotel.java 文件添加一个@Override public String toString() { ... }
方法,该方法打印您想要打印的任何内容。也许就像:return this.hotelName;
.
注意:为了让这些事情变得简单,您可以考虑使用 Project Lombok。那么你需要写的是:
@lombok.Data public class Hotel {
String name,city,phoneNumber;
}
getter、setter 以及 equals、hashCode 和 toString 都只是默默地存在,并具有合理的实现。
免责声明:我为龙目岛项目做出了贡献。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。