5

I do understand that double brace initialization has its own hidden cost, still is there a possible way to initialize Map<String,Map<String,String>>().

What i tried:

Map<String, Map<String, String>> defaultSourceCode = new HashMap<String, Map<String, String>>(){
            {"a",new HashMap<String, String>(){{"c","d"}}}
        };

I know it is a bad practice but as for experiment i am trying it.

Reference and Motivation: Arrays.asList also for maps?

Andronicus
  • 25,419
  • 17
  • 47
  • 88
Vishwa Ratna
  • 5,567
  • 5
  • 33
  • 55
  • Is this even legal Java syntax? –  Mar 12 '19 at 10:04
  • Yeah: https://stackoverflow.com/questions/40449848/arrays-aslist-also-for-maps – Vishwa Ratna Mar 12 '19 at 10:04
  • @LutzHorn, done! – Vishwa Ratna Mar 12 '19 at 10:06
  • 5
    Suggestion: Try avoiding such data structure in favor of concrete classes as much as possible. – Naman Mar 12 '19 at 10:10
  • Possible duplicate of [adding multiple entries to a HashMap at once in one statement](https://stackoverflow.com/questions/8261075/adding-multiple-entries-to-a-hashmap-at-once-in-one-statement) – Naman Mar 12 '19 at 10:12
  • @CommonMan I hope you're aware that "double brace initialized" collections will always keep strong reference to class that declared them. – rkosegi Mar 12 '19 at 10:14
  • @Naman , it is not that what i wanted, I am looking for double brace initialization for map of Map. – Vishwa Ratna Mar 12 '19 at 10:14
  • Double-brace initialization is an antipattern – ZhekaKozlov Mar 12 '19 at 10:16
  • @rkosegi , i read it here https://stackoverflow.com/questions/1958636/what-is-double-brace-initialization-in-java , but if you could explain in much more detail with example in answer, it would help me and others who stumble upon this question, **sharing is caring** :) – Vishwa Ratna Mar 12 '19 at 10:16
  • 2
    @CommonMan https://stackoverflow.com/a/1958961/1121249 and https://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/ – rkosegi Mar 12 '19 at 10:18

2 Answers2

9

You can use Map.of() from java9 that returns an immutable map:

Map<String, Map<String, String>> map = Map.of("a", Map.of("c", "d"));

Or Map.ofEntries :

Map<String, Map<String, String>> map1 = Map.ofEntries(
        Map.entry("a", Map.of("c", "d"))
);
Ruslan
  • 6,090
  • 1
  • 21
  • 36
  • 2
    Liked it and +1 , but i was looking for double brace initialization. Though as always thanks :) – Vishwa Ratna Mar 12 '19 at 10:12
  • In Java 10+ even shorter: `var map = Map.of("a", Map.of("c", "d"));` – ZhekaKozlov Mar 12 '19 at 10:17
  • @Ruslan, i read somewhere that Map.of() , can populate upto 10 items only, right? – Vishwa Ratna Mar 12 '19 at 10:19
  • 1
    @CommonMan yes, and `ofEntries` solves this problem – Ruslan Mar 12 '19 at 10:22
  • 2
    In many cases list of 20 arguments is more than enough to get confused about which are the keys and which are the values. There is a good reason for the restriction. `ofEntries` takes virtually unlimited items and does make it clear which are keys and which are values. – Ole V.V. Mar 12 '19 at 10:44
  • or if you ware stuck with pre-java-8 code : `ImmutableMap::of` from guava – Eugene Mar 12 '19 at 11:14
  • 1
    @OleV.V. well, the good reason for the restriction is that you can’t declare a varargs method supporting distinct key and value types, hence, only overloaded methods with an explicit parameter list can be declared. This may harmonize with your idea that too many arguments are confusing anyway, but the primary reason is purely technical. – Holger Mar 12 '19 at 14:17
  • 1
    @Holger In a homegrown library I have seen a method that accepted `Object...` and returned a map. You could pass an odd number of arguments and get an exception back, or pass the completely wrong types. The technical limitation can be surmounted if the will is strong (needless to say mine isn’t). – Ole V.V. Mar 12 '19 at 14:23
  • 1
    @CommonMan If you can use `Map.of` and friends, great, but if you can’t, you’re probably better off rolling your own utility methods instead of using double brace initialization. – Stuart Marks Mar 13 '19 at 07:02
  • @StuartMarks, i can use Map.of and has been using it, i just wanted to see how stuffs work if i use it in Map of Map. – Vishwa Ratna Mar 13 '19 at 07:04
5

Almost everything is fine, you just have to use method calls in double braces:

Map<String, Map<String, String>> defaultSourceCode = new HashMap<String, Map<String, String>>(){
    {put("a",new HashMap<String, String>(){{put("c","d");}});}
};

But this answer describes, why you shouldn't do that.

Andronicus
  • 25,419
  • 17
  • 47
  • 88
  • Funny, Eclipse wants me to define a `serialVersionUID`for these classes. –  Mar 12 '19 at 10:08
  • 1
    this is a very famous anti-pattern! plz don't. – Eugene Mar 12 '19 at 11:09
  • @Eugene you're absolutely right, I attached more info. – Andronicus Mar 12 '19 at 11:13
  • 2
    @LutzHorn well, that’s a great hint to the problems connected with this anti-pattern. This is creating a subclass of a Serializable class and serializing such map would create a persistent reference to this anonymous class. Of course, adding a `serialVersionUID` would not solve the problems (besides that you can’t do that anyway). E.g., small changes in the surrounding class, like using this anti-pattern again for a different map, can cause renumbering of the class files, which invalidates persistent maps. Not to speak of unintended references to the outer object and any captured variable… – Holger Mar 12 '19 at 14:10