我有以下示例代码,它由3个嵌套的for循环组成。
for(Continent continent : continentList)
{
for(Country country : continent.getCountries())
{
for(City city : country.getCities())
{
//Do stuff with city objects
}
}
}
有没有办法使用Guava和迭代器来模仿这个嵌套的for循环?我一直试图找到一个没有太多运气的合适例子,我想知道是否有人可以帮助我?我的一位同事提到使用过滤器。
编辑:修复了示例代码中的小错误
答案 0 :(得分:11)
正如Peter Lawrey评论的那样,这几乎肯定会像嵌套循环一样简单。更重要的是,Guava documentation会发出此警告:
命令代码应该是您的默认代码,是Java的首选 7.除非您完全确定以下其中一项,否则不应使用功能习语:
- 功能习语的使用将导致代码行的净节省 为您的整个项目。移动定义 函数到另一个文件或常量,没有帮助。
- 为了提高效率,您需要对转换后的懒惰计算视图 集合并不能解决明确计算的集合。 此外,您已阅读并重读了Effective Java,第55项和 除了遵循这些说明,你实际上已经完成了 基准测试证明这个版本更快,并且可以引用 数字来证明这一点。
使用番石榴的功能时请确定 公用事业,传统的必要做事方式不是 更具可读性。试着把它写出来。真是太糟糕了吗?那更多 比你荒谬笨拙的功能方法更可读 即将尝试?
但是,如果你坚持忽略建议,你可以使用像这样的怪物(注意我实际上没有尝试编译或运行它):
FluentIterable.from(continentList)
.transform(new Function<Continent, Void>() {
public Void apply(Continent continent) {
return FluentIterable.from(continent.getCountries())
.transform(new Function<Country, Void>() {
public Void apply(Country country) {
return FluentIterable.from(country.getCities())
.transform(new Function<City, Void>() {
public Void apply(City city) {
// do stuff with city object
return null;
}
});
}
});
}
});
现在问问自己:你想保持哪个?哪个会最有效?
Guava的功能习惯有一些有效的用例。替换Java for循环,甚至嵌套for循环,都不是其中之一。
答案 1 :(得分:8)
您可以定义静态函数:
•Continent,Continents或Functions中的getCountries()
•国家,国家或职能中的getCities()
现在你可以做点什么......
FluentIterable.from(continentList)
.transformAndConcat(Continent.getCountriesFunction())
.transformAndConcat(Country.getCitiesFunction())
. //filter //tranform //find //toList() //etc.
如果:
•您经常使用番石榴(更多)
•对于定义功能和谓词的位置有一定的规则/想法
•有不同(复杂)的东西可以过滤或搜索
然后它可以是一个伟大的福音,可以使许多情况更容易。我知道我很高兴我做到了。
如果你稀疏地使用它,那么我将不得不同意@Louis Wasserman。然后这不值得麻烦。此外,将函数和谓词定义为匿名内部类,就像其他示例一样......真的很难看。
答案 2 :(得分:3)
另一个怪物,使用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();
}
};
}
}
然后调用它:
for (City city: new CityIterable(continentList)) {
System.out.println(city.name);
}
考虑到这种怪异,请遵循ig0774的建议并保留嵌套循环。
P.S。无需过滤器。
答案 3 :(得分:2)
不,没有一个简单的方法。而且,它会比你问题中的for-each循环更冗长。
请参阅http://code.google.com/p/guava-libraries/issues/detail?id=218#c5以及http://code.google.com/p/guava-libraries/wiki/FunctionalExplained
中的警告答案 4 :(得分:1)
我同意其他人的看法,嵌套循环是最有效的方法。但是:我将每个循环级别提取到一个单独的方法,以保持可读性并确保每个方法完成一件事:
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
}
如果你需要在不同的级别上携带一些状态,你有几个选择:将它们放在包含类的成员字段中,将第二个参数传递给所有可以是map或自定义对象的方法。