3

I have some set of data with key-value pairs, but there is only a finite and known set of keys, all of the key should always be present on that data, and they all have the same type for the value. Does it make more sense to use an enum for the key in a map (like Map<SomeEnum, String>) or make a new class to represent this? Both approaches can work but I'm wondering which one makes more sense.

If this data were in JSON it might look something like this.

{
  "alpha": "blah",
  "bravo": "blah blah",
  "charlie": "blah blah blah"
}

My gut instinct is that the class approach is better. My reasoning is that using a Map is more for when you have arbitrary keys or keys that will be unknown at compile time. One of the advantages of a class with getters is that all the possible keys are just there, they are methods essentially. It makes the code more "self documenting" in a sense. The only real downside of this approach is that there is more boilerplate to write (which can be alleviated with things like your IDEs source generation tools).

The code for the class approach would be something like this.

class Data {
  private final String alpha;
  private final String bravo;
  private final String charlie;
  // Constructor and getters omitted for brevity
}

The code for the map approach would be something like this.

enum Key {
  ALPHA, BRAVO, CHARLIE
}
//...
Map<Key, String> data;
  • I hesitate to recommend this generally, but in your case, if you just have final strings, you can skip the getters and make the members public. Your class would then be more struct-like and have less boilerplate. – cbojar Jul 28 '18 at 18:13
  • There's missing context here. Where does the data come from? Where does it go? Do the POJO's you'd be creating represent domain/business entities? Does the application need to know what the fields are? Do the field names need to appear in code for special processing? Or, is it "incidental" that you know what the fields are? It is "pass-through" data? Can you write generic code that doesn't ultimately need to know what the keys are? – svidgen Jul 28 '18 at 19:13
3

I would go with the pojo (object) approach.

Both are quite reasonable. But when you look at usage the object approach is more terse and clear.

And more importantly it generalizes better. Consider if the value associated with one of the names was not a string?

What if it was an integer or an array or another enumeration? It could even be another structure (POJO).


2

It depends on the usage patterns.

I'd generally prefer the POJO version as it's cleaner, safer and easier for the HotSpot optimizer.

But two situations come to my mind where I'd switch to the Map version:

  • If typical instances only fill a small portion of the fields, the Map solution can be more memory-efficient. But right now that's premature optimization, so it shouldn't be done initially, only after finding a memory consumption problem, profiling and identifying your class as the origin of memory hunger.

  • If you need generic getters and setters with the desired key as parameter, a Map supports that quite naturally, whereas the POJO needs either reflection or a long switch statement.

1

Why not using both ?

You can create an object which contains the precisely identified key (alpha, bravo and charlie in your case).

Then include a map which will contains all extra fields.

Using Jackson you can do it easily.

It would look like this:

public class Data {
    private final String alpha;
    private final String beta;
    private final String charlie;

    private final Map<String, Object> extraFields;

    // constructor, getters and setters

    @JsonAnyGetter
    public Map<String, Object> getExtraFields(){
           return extraFields;
    }

    @JsonAnySetter
    public void setExtraField(String key, Object value) {
           extraFields.put(key, value);
    }

}

If you really have to choose between the map approach and the POJO, I would definitely go for POJO.

You will be able have more complexe structure (delta could be an object of type SubData). This structure will be then strongly typed and you won't have to deal with multiple cast. This way, you reduces runtime error possibilities and improve code readability.

0

Use a POJO. For serialization you can use different DTOs which the mapper will then map appropriately.

The advantage is that you can this DTO ~

class DataView1DTO {
  private alpha;
  // getters / setters
}

class DataView2DTO {
  private alpha;
  private charlie;
  // getters / setters
}

You can then use the ObjectMapper to transform a "Data" object either into DataView1DTO or DataView2DTO just like this

Data myData // ...
DataView1DTO dto = myModelMapper.writeValue(myData, DataView1DTO.class);
// or...
DataView2DTO dto = myModelMapper.writeValue(myData, DataView2DTO.class)

and then convert it to JSON like this

String dtoJson = myObjectMapper.writeValueAsString(dto);

A more appropriate example would be user data like password or other sensitive data that you cannot transfer. Or it might depend on on the receiver's privileges, so you would need different kind of "views".

Hope you get what I mean.

0

The (c)leaner and faster approach would be a list or array rather than a map/dictionary. The enum could be just an index if you define it with fixed incrementing values.

To avoid the cast each time you could encapsulate the list/array in a class that offers nice and type-safe getters and setters for your elements. This approach would also allow you to read your data from a file.

  • 1
    This is a wrong approach as far as json is concerned. There is no order in json attributes. This means deserialisation will require to know which properties is linked to which index. Then you come back using properties name. It's better to go for a map then. – Grégory Elhaimer Jul 27 '18 at 9:47
  • @Grégory Elhaimer The serialization is encapsulated in the class, it does not matter how this is done. But suppose you would want your files to be JSON, you would have the enums for names and the list/array values as values. The enum members would be easy to iterate over, that would give you your names. When deserializing, the names could be parsed back to enums. – Martin Maat Jul 27 '18 at 11:48
  • It does not change the fact that it requires ordering properties which is not useful as this notion does not exist in JSON. It only over complexifies something initially simple. Using indexes will provide nothing but useless complexity compared to a simple Map. – Grégory Elhaimer Jul 27 '18 at 11:52
  • As JSON is order-agnostic, it makes no sense to claim that any specific order would be bad. It could be convenient to the human reader. The map is the more complex (and slower, and more memory using) thing here, that was my whole point. Having n integers or n name strings in memory can make a big difference as n gets a bigger number. Whether you care about that or not is up to you. – Martin Maat Jul 27 '18 at 12:09
  • The concern about performance here is pointless. We are talking about mapping JSON which is string parsing at the beginning. As far as reading is concerned, well, I think a POJO will be way better than either map or list. More generally, trying to think about small optimisation is a bad practice as the JVM will handle most of it. In the end, in such simple cases the performance of access should be the last criteria to choose between map and list. – Grégory Elhaimer Jul 27 '18 at 12:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.