Java从嵌套的Stream ForEach中断

u1ehiz5o  于 2023-03-28  发布在  Java
关注(0)|答案(1)|浏览(162)

编辑:将伪代码切换为可运行的代码示例。
编辑2:Sonarlink认为嵌套流降低了认知复杂性,在我的问题末尾添加了结果。谢谢@ Unamended。
我有一些对象,让说;国家,城市,地区。国家有城市列表,城市有地区列表。
我试图找到一个地区的名称,并把这些数据在Map上。
例如:区名是“巴士底”。2我试图通过检查所有国家、所有城市、所有区来找到它。3下面是我的逻辑的示例代码。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class Main {

    public static void main(String[] args) {

        System.out.println("Hello, World!");

        List<Country> countries = new ArrayList<>();

        Country co1 = new Country();
        co1.setName("USA");

        City cit1 = new City();
        cit1.setName("New York");

        District d1 = new District();
        d1.setName("Manhattan");

        District d2 = new District();
        d2.setName("Queens");

        cit1.setDistricts(Arrays.asList(d1, d2));
        co1.setCities(Arrays.asList(cit1));

        countries.add(co1);

        Country co2 = new Country();
        co2.setName("France");

        City cit2 = new City();
        cit2.setName("Paris");

        District d3 = new District();
        d3.setName("Bastille");

        District d4 = new District();
        d4.setName("Montmarte");

        cit2.setDistricts(Arrays.asList(d3, d4));
        co2.setCities(Arrays.asList(cit2));

        countries.add(co1);
        countries.add(co2);


        HashMap<String, HashMap<String, HashMap<String, String>>> foundMap = new HashMap<>();

        boolean isFound = method1(countries, foundMap, "Bastille");

        System.out.println(foundMap);

    }

    public static boolean method1(List<Country> countries, HashMap<String, HashMap<String, HashMap<String, String>>> foundMap, String search) {
        for(Country country : countries){
            for(City city : country.getCities()){
                for(District district : city.getDistricts()){
                    if(district.getName().equals(search)){

                        if(!foundMap.containsKey(country.getName())){
                            foundMap.put(country.getName(), new HashMap<>());
                        }

                        if(!foundMap.get(country.getName()).containsKey(city.getName())){
                            foundMap.get(country.getName()).put(city.getName(), new HashMap<>());
                        }

                        foundMap.get(country.getName()).get(city.getName()).put(district.getName(), "Hello from " + district.getName());

                        return true;
                    }
                }
            }
        }

        return false;
    }
}

这里有国家、城市、地区类的样本;

import java.util.List;

public class Country {

    String name;
    List<City> cities;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<City> getCities() {
        return cities;
    }

    public void setCities(List<City> cities) {
        this.cities = cities;
    }
}

import java.util.List;

public class City {

    String name;
    List<District> districts;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<District> getDistricts() {
        return districts;
    }

    public void setDistricts(List<District> districts) {
        this.districts = districts;
    }
}

public class District {

    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

这个例子为我创建了所需的HashMap;
巴黎:你好,巴士底狱
在我的情况下,我需要检查method 1的返回,如果没有找到这个地区,就抛出一个异常!(系统应该包含所有的地区,所以“没有找到”是一个失败)
我还需要所有这些国家名、城市名、地区名(这些嵌套的for循环提供给我)来创建这个HashMap条目。
那么有没有更优雅的方法来用流或其他工具实现这种逻辑呢?(我对这段代码没问题,但sonarlint对“认知复杂性”不满意,我必须找到一种方法来降低它)。
尝试切换到嵌套流,但我不知道如何在这里使用流。我可以使用一些嵌套流,但我无法返回true。

countries.getCities().forEach(city->{
...
...
//if district name is Bastille
return true; //Unexpected Return value because this is inside nested streams, not returning true from the method. If only "return" is used, I only returns from iterable to the outer stream.
}

那么,有没有更好的方法来使“检查是否存在区域”和“将所有数据放入散列表”逻辑运行?或者解决这个问题的唯一方法是改变算法?

结论:我把我的代码切换到Unamended的答案。

在我的真实的情况中,我必须创建4个“for”循环,然后是一个“if”来检查条件是否满足,然后是一些带有hashmap的业务逻辑。Sonarlink认为方法的认知复杂度是30。
在切换到使用anyMatch的嵌套流之后,一个内部布尔变量检查是否满足条件,然后使用hashmap和返回的一些业务逻辑;Sonarlink现在说认知复杂度下降到了20。我认为这是Sonarlink的误判,因为它忽略了“stream().anyMatch(...”,但却把“for(Obj o:列表)”。
问题是:我的公司不允许在方法中有更高级别的复杂性,在此重构Sonarlink后很高兴。

roejwanj

roejwanj1#

您可以使用嵌套的Stream#anyMatch(这是一种短路操作),但它并不能真正降低认知复杂性。

return Countries.stream().anyMatch(country -> 
    country.getCities().stream().anyMatch(city -> 
        city.getDistricts().stream().anyMatch(district -> {
            boolean ret = district.getName().equals(search);
            if (ret) {
                // do something
            }
            return ret;
        })
    )
);

相关问题