简体   繁体   中英

Java HashMap : key is combination of two Enum values. Is there any inbuilt function to check is really a concat of two enums

I want to create a HashMap in java, where key is String type which is concat of two enums.

Sample:

Enum1: public enum Type1{NONE,VALIDATE,CONFIGURE}

Enum2: public enum Type2{A,B,C}

Map declaration: Map<String, Class<? extends InterfaceTest>> enumClassMap Map<String, Class<? extends InterfaceTest>> enumClassMap

Ex1: enumClassMap.put(Type2.A.name()+Type1.VALIDATE.name(),Test1.class) This is valid one, because key is concat of two enums.

Ex2: enumClassMap.put(Type2.A.name(),Test1.class) This one is invalid, because key is not a concat of two enums.

I want to check whether key is really a concat of Type1 and Type2.

I can write separate code to iterate all the keys and validate. But I want to know is there any inbuilt function to do that? My expectation is, java should throw error or exception by default if this is not a combination of enums.

Of course not.

But, the principle , of course yes. Java is very nominal . Types should accurately describe what they represent, and should be as specific as they can be.

Case in point: String is very general, and does not at all describe the notion of 'the concatenation of the name of an enum from type com.foo.raghavan.Type1 and com.foo.raghavan.Type2 .

Conclusion: String is not correct here .

To achieve this ideal of having highly descriptive and specific type names, you must make your own types. A lot. Then this problem fixes itself!

Your names are too general to come up with good names, and good names are important. So, let's say that Type1 is CardSuit (and has values CLUBS, SPADES, etc), and Type2 is CardRank (with values TWO , KING , ACE , etc), then you'd make:

import lombok.Value;
import lombok.NonNull;

@Value
public class Card {
  @NonNull CardSuit suit;
  @NonNull CardRank rank;
}

Map<Card, Class<? extends InterfaceTest>> map;

This has all sorts of advantages:

  • It is simply impossible to make an instance of Card unless you supply 1 valid rank and 1 valid suit. Period. There is just one constructor that makes Card objects and it demands you pass in a rank and a suit, and won't accept null values either.
  • If you have a key (eg when you iterate over the map's entrySet() and call .getKey() ), instead of trying to break that string back out into constituent parts which is quite convoluted, you can just.. call .getRank() and .getSuit() on it! Isn't that nice! It doesn't really matter that you don't need this right now . Maybe you need it tomorrow).
  • The statement now reads far more usefully. Map<String, Class<? extends Thingie> enumMap Map<String, Class<? extends Thingie> enumMap means almost nothing . If I print that out on its own and walk through a java conference and ask people what this map might do they, obviously, have no clue at all. Even if I also print out the API of String . Whereas if I show them: Map<Card, Integer> scoreValues; , and I also show them the API of Card (namely: It has getRank and getSuit ), then just about everybody will tell me: Oh, I see. This probably is some sort of card game where certain cards contribute something to your score at the end or some such. Way closer, in other words.

NB: The snippet uses Project Lombok - because whilst java works way better if you use specific types (which requires making lots of types), making a type that actually 'works well' (can be used as keys in maps, for example), you need lots of boilerplate: getters, a constructor, toString, and equals/hashCode methods, which is tricky to do well. Your IDE can generate it but now you have tons of code to maintain. Project Lombok is one way out. If you're on a rather recent version of java, for simple cases such as this, public record Card {CardSuit suit; CardRank rank;} public record Card {CardSuit suit; CardRank rank;} can help, though you'll have to add your own nullchecking code, and unlike Project Lombok you can't easily make builders for such things.

DISCLAIMER: I'm a core contributor to Project Lombok.

Instead of having a Map<String,...> why not have a Map<Type1, Map<Type2, ...>> ? As long as you specify Type1 first in the groupings, you can immediately check if it is a valid pair by doing the following:

Type1 type1 = <some type one>
if (map.containsKey(type1)) {
   //if true it must contain a type2 mapping.
}

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