简体   繁体   中英

Converting ArrayList of enums to String

I have the following enum s, which can fill an ArrayList :

public enum RewardType {
    POINTS, MONEY, TOKENS, RANDOM;
}

and

public enum OfferType {
    GIFT, DISCOUNT, LOTTERY;
}

To convert the ArrayList to String I use this method:

public static String arrayListToString(ArrayList<Enum> arrayList) {
    String finalString = "";
    for (int i = 0; i < arrayList.size(); i++) {
        if (TextUtils.isEmpty(finalString)) {
            finalString = arrayList.get(i).name();
        } else {
            finalString = finalString + ", " + arrayList.get(i).name();
        }
    }
    return finalString;
}

and then I call it like this:

String rewardType = arrayListToString(mainModel.getRewardTypes()); 
//getRewardTypes returns an ArrayList<RewardType>

The problem is, that arrayListToString is called with ArrayList<Enum> and cannot be called with ArrayList<enum> parameter (which is the type of my classes). I also cannot create a class with type Enum . Since enum != Enum , how do I make arrayListToString method work with my enum classes?

Change the signature of arrayListToString() from this:

 public static String arrayListToString(ArrayList<Enum> arrayList) 

to this:

public static String arrayListToString(ArrayList<? extends Enum> arrayList)

The core concept at play is that a List<Integer> is not a List<Number> , even though an Integer is a Number . This makes sense, because you could put a Double into a List<Number> but you could not put a Double into a List<Integer> .

Similarly, a List<RewardType> is not a List<Enum> , even though a RewardType is an Enum .

A List<RewardType> is , though, a List<? extends Enum> List<? extends Enum> . This is because we now are saying that the list is a list of some sort of enum , not a list of any enum ever .

Since an enum X is implicitly a subclass of Enum<X> , change method declaration to:

public static String arrayListToString(ArrayList<? extends Enum> arrayList)

However, why do that?

The toString() of a enum returns the name() by default, so you don't need to call name() , which means you don't really care what's in the list anymore, so this much more generally useful method will work too:

public static String listToString(List<?> list) {
    StringBuilder buf = new StringBuilder();
    boolean first = true;
    for (Object value : list) {
        if (first)
            first = false;
        else
            buf.append(", ");
        buf.append(value);
    }
    return buf.toString();
}

It can be even simpler than that:

public static String toString(Iterable<?> iterable) {
    StringJoiner joiner = new StringJoiner(", ");
    for (Object value : iterable)
        joiner.add(String.valueOf(value));
    return joiner.toString();
}

Or with Java 8+ streams:

public static String toString(Collection<?> coll) {
    return coll.stream().map(Object::toString).collect(Collectors.joining(", "));
}

As mentioned by Ben, You should use type generics to properly evaluate the type.

Aside from that, your method is slightly unoptimized. Consider using StringBuilder to prevent creation of garbage String objects, and remove redundant isEmpty check inside your loop:

public static <T extends Enum<?>> String enumListToString(List<T> list){
    if(list.size() < 1)
        return "";
    StringBuilder sb = new StringBuilder();
    sb.append(list.get(0).name());
    for (int i = 1; i < list.size(); i++) {
        sb.append(", ").append(list.get(i));
    }
    return sb.toString();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM