2

Im curious, in JavaScript is effective way to write a function constructor using options object which helps instance creation since you don't have to remember what variable goes to what spot and the reader can see without going inside the declaration what these values means and don't need to care about order of provided parameters.

Example:

var Dog = function(options) {
    this.name = options.name;
    this.age = options.age;
    this.weight = options.weight;
};

// This is the part I'am interested in
var dog = new Dog({ 
    name: "luffy", 
    age: 7, 
    weight: 23
});

The question is, what is the closest code which could mimic this functionality in Java, or is there any? If not, why not?

To clarify:

I'am interested in visibility aspects of JavaScript notation and that I don't need to care about order or provided values, using Java format: new Dog("luffy", 7); won't tell me what is i.e. 7 and it requires me to provide values in specified order for the class.

5
  • It's not just constructors. Lots of non-constructor functions accept options objects as well. jQuery's $.ajax comes to mind as a common example... Commented Jan 8, 2014 at 7:40
  • Possible duplicate of Named Parameter idiom in Java, which has this excellent answer. Commented Jan 8, 2014 at 7:42
  • Use Java Map Object ;) Commented Jan 8, 2014 at 7:42
  • @Markku: Think about the syntax of doing that for a second... Commented Jan 8, 2014 at 7:42
  • My answer was incorrect, not the code (which was okay) but I'd misunderstood the answer I linked to, which actually does what my code did, but arguably better. I've updated my answer. Commented Jan 9, 2014 at 8:32

2 Answers 2

1

Updated

I originally misread this answer, which describes the idiom for this from Effective Java 2nd Edition. I thought it didn't do something it does do, and so this answer is really just a duplicate of that answer (except that that answer's syntax was better). I've marked this answer as a CW.

I'm leaving this intact, though, since it was apparently of some use to the OP. But I'm posting the other answer's syntax below.

The solution from Effective Java 2nd Edition is to have the constructor accept an "options" object using the builder pattern (Foo.Options below). This is so the real object is either fully-constructed or not constructed, but never half-constructed; the Foo.Options instance may be half-constructed, but we don't care as it's just an options class. This also lets us put the logic around duplicated options or missing options in a nice separate (but contained) class.

Here's what it looks like to use: (but note that the Effective Java syntax is even simpler, see below)

Foo f = new Foo((new Foo.Options()).first("primero").second("secondo"));

(Foo could also provide a positional-arguments constructor if desired, as an option, for callers who wanted to use that; see note after the big code block.)

Here's what Foo (and Foo.Options) look like:

public class Foo {

    public Foo(Foo.Options opts) {
        if (!opts.isValid()) {
            // Throw exception
        }

        // Use options
    }

    public static class Options {
        private String _first = null;
        private String _second = null;

        public Options() {
        }

        public Options(String f, String s) {
            this.first(f).second(s);
        }

        public boolean isValid() {
            return this._first != null && this._second != null;
        }

        public Options first(String f) {
            this._first = f;
            return this;
        }

        public String getFirst() {
            return this._first;
        }

        public Options second(String s) {
            this._second = s;
            return this;
        }

        public String getSecond() {
            return this._second;
        }
    }
}

Of course, if you also wanted to allow positional arguments, you could define a Foo constructor accepting them. To avoid having arguments logic repeated in both Foo and Foo.Options, that constructor would probably just call the Foo.Options version, e.g.:

// *Optional* additional positional constructor for `Foo`
public Foo(String first, String second) {
    this((new Foo.Options()).first(first).second(second));
}

Here's the code and usage from the answer I misread originally. The big difference is that instead of Foo.Options, we have Foo.Builder, and Foo.Builder returns a Foo when we ask it to build:

Foo foo = Foo.builder()
    .setColor(red)
    .setName("Fred")
    .setSize(42)
    .build();

Here's Foo and Foo.Builder:

public class Foo {
  public static class Builder {
    public Foo build() {
      return new Foo(this);
    }

    public Builder setSize(int size) {
      this.size = size;
      return this;
    }

    public Builder setColor(Color color) {
      this.color = color;
      return this;
    }

    public Builder setName(String name) {
      this.name = name;
      return this;
    }

    // you can set defaults for these here
    private int size;
    private Color color;
    private String name;
  }

  public static Builder builder() {
      return new Builder();
  }

  private Foo(Builder builder) {
    size = builder.size;
    color = builder.color;
    name = builder.name;
  }

  private final int size;
  private final Color color;
  private final String name;

  // The rest of Foo goes here...
}
Sign up to request clarification or add additional context in comments.

2 Comments

Pretty good, but if I would only read a line: Foo f = new Foo((new Foo.Options("primero", "secondo")); this still would not tell me what is parameter primero or secondo as javascript notation { name: "luffy", age: 7 } would tell it right away. ? I dont get the point of using this over normal new Dog("luffy", 7); visibility, is as bad as before?
@MaunoV.: I said "if the caller wants to use positional notation." The primary form would be the Foo f = new Foo((new Foo.Options()).first("primero").second("secondo")); one. The only reason for providing positional in Foo.Options rather than Foo would be keeping the logic for arguments in Foo.Options, but actually you could do that anyway even if Foo accepted positional args (optionally) as well as a Foo.Options object.
1

Use Java Map Object ;)

Map<String, Object> params = new HashMap<String, Object>>(){{
    put("name", "luffy");
    put("age", 7);
    put("weight", 23);
}};


Dog dog = new Dog(params);

5 Comments

If I encountered a library that made me call its methods that way, the library would be deleted so fast its bits would be spinning.
I know, but this is one way of doing this :)
I think you are missing <String, Object> with HashMap creation
@MaunoV.: The empty <> is Java 7 syntax telling the compiler to infer it from the type of the variable being initialized.
Aaaa.. have been using too much Java 6

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.