3

I got a pretty simple question but couldn't find anything so far.

I'm trying to create two class constructors.
The first constructor gets 2 Strings and one HashMap and initializes the class variables.

public Foo(String a, String b, HashMap<String, String> c) {
    this.a = a;
    this.b = b;
    this.c = c;
}

The second constructor should only get the 2 Strings and create a "default"-HashMap.

Usually you just call this() with the default-value inside but I could not find a way to do this with a HashMap.

public Foo(String a, String b) {
    this(a, b, new HashMap<String, String>().put("x", "y").put("f","g"));
}

Eclipse marks an error:

Type mismatch: cannot convert from String to HashMap<String,String>

And otherwise the this()-call cannot be the first statement in the function.

public Foo(String a, String b) {
    HashMap<String, String> c = new HashMap<String, String>();
    c.put("x", "y");
    c.put("f", "g");
    this(a, b, c);
}

Any ideas how to solve this?

Worst case I had to duplicate the code, but I was wondering if there is no better way.

2
  • 2
    your reference to c will still be the same. you could simply use this(a, b, new HashMap<String, String>()); as your first statement and go on working with c. Commented Nov 24, 2015 at 13:44
  • 1
    Map<K,V>'s put returns current value (V). Hence you get the TypeMismatch. Commented Nov 24, 2015 at 13:48

5 Answers 5

5

If this Map is a constant, you could store it as a constant and reuse it. This avoids recreation of the Map each time a new Foo is created but it is then shared across all Foos.

public class Foo {

    private static final Map<String, String> DEFAULT = new HashMap<>();

    static {
        DEFAULT.put("x", "y");
        DEFAULT.put("f","g");
    }

    public Foo(String a, String b) {
        this(a, b, DEFAULT);
    }

    public Foo(String a, String b, Map<String, String> c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

}

You could also create a static method returning the correct value. Note that the method needs to be static because you can't call an instance method inside this().

public class Foo {

    public Foo(String a, String b) {
        this(a, b, getDefaultMap());
    }

    public Foo(String a, String b, Map<String, String> c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    private static Map<String, String> getDefaultMap() {
        Map<String, String> map = new HashMap<>();
        map.put("x", "y");
        map.put("f", "g");
        return map;
    }

}
Sign up to request clarification or add additional context in comments.

Comments

4

It´s unneccessary to create a local variable of c.

You could simply call it like this.

public Foo(String a, String b) {
    this(a, b, new HashMap<String, String>());
    c.put("x", "y");
    c.put("f", "g");
}

Since your other constructor this(String, String, HashMap<String, String>()) will assign the new HashMap to c invoking methods on c will also fill this newly created HashMap and will assign the default values that you did provide to it.

Another solution could be to create a static method and just call it

public static HashMap<String, String> createDefaultHashMap() {
    HashMap<String, String> c = new HashMap<String, String>();
    c.put("x", "y");
    c.put("f", "g");
    return c;
}

public Foo(String a, String b) {
    this(a, b, Foo.createDefaultHashMap());;
}

Comments

1

The HashMap method .put returns a String so you are passing a String when calling the 3 argument constructor in your 2 argument constructor.

Comments

0

You can do a trick like this:

public Foo(String a, String b) {
    this(a, b, new HashMap<String, String>(){
       {
           put("x", "y");
           put("f", "g");
       }
    });
}

It creates anonymous class that inherits HashMap and defines init block with putting values.

2 Comments

This is called double-brace initialization but I'm not sure if I would recommend it.
Yes but do note that it creates an anonymous inner class. More info here.
0

You can work around the "call to this() must be the first statement" by adding a static method that creates your default Map instance:

public Foo(String a, String b) {
    this(a, b, createDefaultMap());
}

private static Map<String, String> createDefaultMap() {
    Map<String, String> defaultMap = new HashMap<String, String>();
    defaultMap.put("x", "y");
    defaultMap.put("f", "g");

    return defaultMap;
}

It is mandatory that createDefaultMap() is static, as you may not access the half-constructed instance at this point.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.