Java Guava迭代器,并在列表对象内的列表上迭代
下面的示例代码由3个嵌套for循环组成Java Guava迭代器,并在列表对象内的列表上迭代,java,iterator,guava,Java,Iterator,Guava,下面的示例代码由3个嵌套for循环组成 for(Continent continent : continentList) { for(Country country : continent.getCountries()) { for(City city : country.getCities()) { //Do stuff with city objects } } } 有没有办法使用Guava和
for(Continent continent : continentList)
{
for(Country country : continent.getCountries())
{
for(City city : country.getCities())
{
//Do stuff with city objects
}
}
}
有没有办法使用Guava和迭代器来模拟这个嵌套for循环?我一直在努力寻找一个不太幸运的合适的例子,我想知道是否有人能帮我解决这个问题?我的一位同事提到使用过滤器
编辑:修复了示例代码中的小错误不,没有简单的方法。而且,它将比问题中的for each循环更加冗长
正如Peter Lawrey评论的那样,这几乎肯定会比嵌套循环更简单。除此之外,还发出以下警告: 命令式代码应该是您的默认代码,作为Java的首选 7.除非您完全确定以下情况之一,否则不应使用功能性习惯用法:
- 使用函数式习惯用法将净节省代码行 为了你的整个项目。移动定义 将一个函数复制到另一个文件或常量也无济于事李>
- 为了提高效率,您需要一个延迟计算的转换视图 集合,无法满足显式计算的集合。 此外,您已经阅读并重新阅读了有效Java,第55项,以及 除了遵循这些说明之外,你实际上已经做到了 基准测试证明这个版本更快,并且可以引用 数字证明了这一点李>
fluenterable.from(列表)
.transform(新函数(){
公共无效申请(大陆){
返回fluentitable.from(contraction.getCountries())
.transform(新函数(){
公共无效申请(国家/地区){
返回fluentitable.from(country.getCities())
.transform(新函数(){
公共无效申请(城市){
//用城市物体做东西
返回null;
}
});
}
});
}
});
现在问问你自己:你想维持哪一个?哪一个将是最有效的
番石榴的功能性习语有一些有效的用例。将Java替换为循环(甚至嵌套为循环)不是其中之一。另一个怪物,使用AbstractIterator:
class CityIterable implements Iterable<City> {
List<Continent> continents;
CityIterable(List<Continent> continents) {
this.continents = continents;
}
@Override
public Iterator<City> iterator() {
return new AbstractIterator<City>() {
Iterator<Continent> continentIterator = continents.iterator();
Iterator<Country> countryIterator;
Iterator<City> cityIterator;
@Override
protected City computeNext() {
if (cityIterator != null && cityIterator.hasNext()) {
return cityIterator.next();
}
if (countryIterator != null && countryIterator.hasNext()) {
cityIterator = countryIterator.next().getCities().iterator();
return computeNext();
}
if (continentIterator.hasNext()) {
countryIterator = continentIterator.next().getCountries().iterator();
return computeNext();
}
return endOfData();
}
};
}
}
考虑到这种可怕的情况,请遵循ig0774的建议并保留嵌套循环
另外,不需要过滤器。我同意其他人的观点,嵌套循环是最有效的方式。但是:我会将每个循环级别提取到一个单独的方法中,以保持可读性并确保每个方法只做一件事:
public void doStuffWithWorld(World world){
for (Continent continent : world.getContinents()) {
doStuffWithContinent(continent);
}
}
private void doStuffWithContinent(Continent continent) {
for (Country country : continent.getCountries()) {
doStuffWithCountry(country);
}
}
private void doStuffWithCountry(Country country) {
for(City city : country.getCities()){
doStuffWithCity(city);
}
}
private void doStuffWithCity(City city) {
// do stuff here
}
如果您需要在不同的级别执行某些状态,您有几个选项:将它们放在包含类的成员字段中,向所有方法传递第二个参数,这些方法可以是映射或自定义对象。您可以为以下对象定义静态函数:
•获取大陆、大陆或功能中的国家(
•getCities()位于国家/地区、国家/地区或职能部门
现在你可以做一些像
FluentIterable.from(continentList)
.transformAndConcat(Continent.getCountriesFunction())
.transformAndConcat(Country.getCitiesFunction())
. //filter //tranform //find //toList() //etc.
如果:•像这样(更多)使用番石榴。
•并对定义函数和谓词的位置有一定的规则/想法。
•有各种各样(复杂)的东西要过滤或搜索。
然后,它可以是一个巨大的恩惠,可以使许多情况下相当容易一点。我知道我很高兴我做到了。
如果你很少使用它,那么我必须同意@Louis Wasserman。那就不值得这么麻烦了。此外,像其他示例一样,将函数和谓词定义为匿名内部类。。。非常难看。您可以嵌套映射。至少对于外部循环来说,作为嵌套循环可能更简单。在第3行中,这不应该是“Continental.getCountries()”?您可以使用guavas“transform”和“concat”创建一个三元组列表,然后对其进行迭代,但至少对于Java 7,代码将相当难看。我会继续使用嵌套循环。使用,您可以链接转换,而不是嵌套它们。@FrankPavageau:True。但是,即使这会更干净一点,它仍然会比嵌套循环更难看,可读性更低。@ig0774感谢专业提示:)我真的很喜欢你的建议;如果需要的话,还将对每个单独的活套功能进行单元测试。谢谢:)
public void doStuffWithWorld(World world){
for (Continent continent : world.getContinents()) {
doStuffWithContinent(continent);
}
}
private void doStuffWithContinent(Continent continent) {
for (Country country : continent.getCountries()) {
doStuffWithCountry(country);
}
}
private void doStuffWithCountry(Country country) {
for(City city : country.getCities()){
doStuffWithCity(city);
}
}
private void doStuffWithCity(City city) {
// do stuff here
}
FluentIterable.from(continentList)
.transformAndConcat(Continent.getCountriesFunction())
.transformAndConcat(Country.getCitiesFunction())
. //filter //tranform //find //toList() //etc.