重构 - 从枚举生成字符串列表

发布于 2025-01-15 19:16:08 字数 2543 浏览 2 评论 0 原文

方法 getContinent() 需要一个 String 作为参数,该参数可以具有三个可能的值:"Africa""Asia"和<代码>“欧洲”

根据我得到的给定值,我必须匹配适当的枚举并获取其所有值的列表(作为字符串)。

我的代码中有重复。 有更好的方法吗? 将其放入每个 enum 中是个好主意吗?

Stream.of(CountryAsia.values())
      .map(country -> country.getName())
      .collect(Collectors.toList());

我的代码

Main 类:

public class Main {
    public static void main(String[] args) {
        String continent = getContinent() //one of three possible values: "Africa" or "Asia" or "Europe"
        List<String> list = null;

        switch(continent) {
            case "Africa":
                list = Stream.of(CountryAfrica.values())
                        .map(country -> country.getName())
                        .collect(Collectors.toList());
                break;
            case "Asia":
                list = Stream.of(CountryAsia.values())
                        .map(country -> country.getName())
                        .collect(Collectors.toList());
                break;
            case "Europe":
                list = Stream.of(CountryEurope.values())
                        .map(country -> country.getName())
                        .collect(Collectors.toList());
                break;
        }

        System.out.println(list);
        //next instructions..
    }
}

CountryEurope 枚举:

public enum CountryEurope {
    DENMARK("Denmark"),
    ESTONIA("Estonia"),
    ICELAND("Iceland");

    CountryEurope(String name) {
        this.name = name;
    }

    private final String name;

    public String getName() {
        return name;
    }
}

CountryAsia 枚举:

public enum CountryAsia {
    AFGHANISTAN("Afghanistan"),
    KAZAKHSTAN("Kazakhstan"),
    UNITED_ARAB_EMIRATES("United Arab Emirates"),
    UZBEKISTAN("Uzbekistan");

    CountryAsia(String name) {
        this.name = name;
    }

    private final String name;

    public String getName() {
        return name;
    }
}

CountryAfrica 类:

public enum CountryAfrica {
    ALGIERIA("Algeria"),
    WESTERN_SAHARA("Western Sahara"),
    EGYPT("Egypt");

    CountryAfrica(String name) {
        this.name = name;
    }

    private final String name;

    public String getName() {
        return name;
    }
}

Method getContinent() expects a String as an argument which can have three possible values: "Africa", "Asia" and "Europe".

Depending on the given value I get, I have to match the appropriate enum and get a list of all its values (as String).

There are repetitions in my code.
Is there a better way to do it?
Is it a good idea to place this in each of the enum's?:

Stream.of(CountryAsia.values())
      .map(country -> country.getName())
      .collect(Collectors.toList());

My code

Main class:

public class Main {
    public static void main(String[] args) {
        String continent = getContinent() //one of three possible values: "Africa" or "Asia" or "Europe"
        List<String> list = null;

        switch(continent) {
            case "Africa":
                list = Stream.of(CountryAfrica.values())
                        .map(country -> country.getName())
                        .collect(Collectors.toList());
                break;
            case "Asia":
                list = Stream.of(CountryAsia.values())
                        .map(country -> country.getName())
                        .collect(Collectors.toList());
                break;
            case "Europe":
                list = Stream.of(CountryEurope.values())
                        .map(country -> country.getName())
                        .collect(Collectors.toList());
                break;
        }

        System.out.println(list);
        //next instructions..
    }
}

CountryEurope enum:

public enum CountryEurope {
    DENMARK("Denmark"),
    ESTONIA("Estonia"),
    ICELAND("Iceland");

    CountryEurope(String name) {
        this.name = name;
    }

    private final String name;

    public String getName() {
        return name;
    }
}

CountryAsia enum:

public enum CountryAsia {
    AFGHANISTAN("Afghanistan"),
    KAZAKHSTAN("Kazakhstan"),
    UNITED_ARAB_EMIRATES("United Arab Emirates"),
    UZBEKISTAN("Uzbekistan");

    CountryAsia(String name) {
        this.name = name;
    }

    private final String name;

    public String getName() {
        return name;
    }
}

CountryAfrica class:

public enum CountryAfrica {
    ALGIERIA("Algeria"),
    WESTERN_SAHARA("Western Sahara"),
    EGYPT("Egypt");

    CountryAfrica(String name) {
        this.name = name;
    }

    private final String name;

    public String getName() {
        return name;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暮光沉寂 2025-01-22 19:16:08

您可以使用 EnumSet.allOf() 以便获取 enum 常量的名称。

EnumSet.allOf() 需要一个 enumClass 作为参数,并返回其 EnumSet元素(这是特殊的实现专门为enum设计的Set)。

然后,我们可以使用或纯文本将enum常量的Set转换为字符串列表 for 循环。

如果您使用的是Java 14 +,则可以使用切换表达式。否则,用方法调用替换重复的流语句。

为了使用这些enum中的每个元素(无论其类型如何)访问方法getName(),我们可以定义一个接口,其中所有他们将实施。这样它将作为所有国家/地区枚举入口点

public interface CountryData {
    String getName();
}

此外,它还可能包含一些与特定于域的信息相关的其他方法,这些信息可能在您的应用程序中有用,例如国家/地区或地区税率(所有这些行为都可以通过 CountryData 接口访问)。

结合上面提到的所有内容将给出非常简洁且富有表现力的代码:

public static List<String> getCountries(String continent) {
    return switch(continent) {
        case "Africa" -> getEnumNames(CountryAfrica.class);
        case "Asia" -> getEnumNames(CountryAsia.class);
        case "Europe" -> getEnumNames(CountryEurope.class);
        default -> Collections.emptyList();
    };
}

public static <T extends Enum<T> & CountryData> List<String> getEnumNames(Class<T> enumClas) {
    return EnumSet.allOf(enumClas).stream()
            .map(CountryData::getName)
            .collect(Collectors.toList());
}

上面的方法声明了一个有界类型参数 ; & CountryData>,这意味着任何类型 T 都是 Enum 类和接口 CountryData

具有多个边界的类型变量是所有类型的子类型
列在绑定中。如果其中一个边界是类,则它必须是
首先指定。

有关泛型方法语法的信息,请查看本教程

main()

public static void main(String[] args) {
    System.out.println(getCountries("Europe"));
    System.out.println(getCountries("Africa"));
    System.out.println(getCountries("Asia"));
}

输出

[Denmark, Estonia, Iceland]
[Algeria, Western Sahara, Egypt]
[Afghanistan, Kazakhstan, United Arab Emirates, Uzbekistan]

将其放入每个枚举中是个好主意吗?

不,这并不是因为:

  • 代码不会消除重复,相同的行会分散在多个文件中;
  • 此代码并不特定于您的任何枚举,因此它必须驻留在一个位置(在用于处理此列表的类中)。

You can make use EnumSet.allOf() in order to get the names of your enum constants.

EnumSet.allOf() expects a Class<T> of enum as an argument and returns an EnumSet of its elements (which is special implementation of the Set designed exclusively for enums).

Then we can transform a Set of enum constants into a list of strings either by using a stream or a plain for loop.

And if you are using Java 14 +, you cane utilize switch expressions. Otherwise, replace the repeating stream statement with a method call.

In order to access the method getName() with every element of these enums regardless of its type, we can define an interface which all of them will implement. So that it'll serve as an entry-point to all country-enums.

public interface CountryData {
    String getName();
}

Also, it could contain some other methods related to the domain-specific information that could be useful in your application, like country area or locale tax rates (all this behavior will be accessible though the CountryData interface).

Combining all mentioned above will give a very concise and expressive code:

public static List<String> getCountries(String continent) {
    return switch(continent) {
        case "Africa" -> getEnumNames(CountryAfrica.class);
        case "Asia" -> getEnumNames(CountryAsia.class);
        case "Europe" -> getEnumNames(CountryEurope.class);
        default -> Collections.emptyList();
    };
}

public static <T extends Enum<T> & CountryData> List<String> getEnumNames(Class<T> enumClas) {
    return EnumSet.allOf(enumClas).stream()
            .map(CountryData::getName)
            .collect(Collectors.toList());
}

Method above declares a bounded type parameter <T extends Enum<T> & CountryData>, which implies any type T which is subtype of both Enum class and interface CountryData.

A type variable with multiple bounds is a subtype of all the types
listed in the bound. If one of the bounds is a class, it must be
specified first.

for information on the syntax of generic methods, take a look at this tutorial

main()

public static void main(String[] args) {
    System.out.println(getCountries("Europe"));
    System.out.println(getCountries("Africa"));
    System.out.println(getCountries("Asia"));
}

Output

[Denmark, Estonia, Iceland]
[Algeria, Western Sahara, Egypt]
[Afghanistan, Kazakhstan, United Arab Emirates, Uzbekistan]

Is it a good idea to place this in each of the enum's?

No, it's not because:

  • the code it will not eliminate the duplication, the same lines will be scattered across multiple files;
  • this code ins't specific to any of your enums therefore it must reside in one place (in a class that is meant to process this list).
只怪假的太真实 2025-01-22 19:16:08

看起来您尝试在枚举中存储一些数据集合,恕我直言,这有点错误。我更愿意提供一张地图,其中键是“大陆”,值是国家/地区的集合。映射<字符串,集合>。

然后,你不需要使用开关,你可以使用Map#get()。

Looks like you try to store some collection of data inside enum that is a bit wrong IMHO. I would prefer to provide a map where the key is "continent" and the value is a collection of countries. Map<String, Set>.

Then, you don't need to use the switch, you can use Map#get().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文