71

Like this one? http://weblogs.asp.net/dwahlin/archive/2007/09/09/c-3-0-features-object-initializers.aspx

Person p = new Person()
{
    FirstName = "John",
    LastName = "Doe",
    Address = new Address()
    {
        Street = "1234 St.",
        City = "Phoenix"
    }
};
Hao
  • 8,047
  • 18
  • 63
  • 92

7 Answers7

86

Actually, there is!

Person p = new Person()
{{
    setFirstName("John");
    setLastName("Doe");
    setAddress(new Address()
    {{
        setStreet("1234 St.");
        setCity("Phoenix");
    }});
}};

or even:

Person p = new Person()
{{
    firstName = "John";
    lastName = "Doe";
    address = new Address()
    {{
        street = "1234 St.";
        city = "Phoenix";
    }});
}};

This is called double brace initialization. However I would avoid this idiom as it has some unexpected side-effects, e.g. this syntax actually creates an anonymous inner class Person$1 and Address$.

See also

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 12
    Of course, that also requires that your fields are only protected. While the two forms *look* similar on the surface, they're really very different. – Jon Skeet Feb 02 '12 at 07:33
  • @JonSkeet what you mean? – Hassan Faghihi Nov 24 '16 at 14:35
  • 1
    @deadManN: I mean that if the fields are private (as they typically are) the second form certainly won't work, as it's trying to set fields from a subclass. – Jon Skeet Nov 24 '16 at 14:37
  • side effect? anonymous? is it readable by hibernate? i set my object, and pass it's variable, but for other relational links, i passed a newly created class, which only has the Id of that object... well i'm not sure even if hibernate accept it as if i generate a real class, not anonymous one, but that's what i do in C# with EF(Entity Framework) – Hassan Faghihi Nov 24 '16 at 14:38
  • @JonSkeet i didn't test it in all ways, but some where i got error before. but i use it with getter/setter is that ok? `new Work(){{ setTime(work.getTime()); setPerson(new Person(){{ setId(work.getPersonId())}} ) }}` – Hassan Faghihi Nov 24 '16 at 14:41
  • @deadManN: Well I wouldn't personally do it, as you're creating a new class in each code location where you do this, and the double braces look ugly to me, but yes, it would work... As for whether it will work with Hibernate etc, I've no idea. But you need to understand how different this is to the C# code. – Jon Skeet Nov 24 '16 at 14:43
  • well, that why if i want to say new work(), and then set all properties, and then before that i create person and do the same, and also other classes that my also are included, it become lot of massive code that is not understandable at all. but maybe you have better idea. BTW, the java community that i admire knows lots of design pattern and can think of many thing that our C# community folks are unable, because we naturally don't need that much, as it's name everything by default is sharper toward java. – Hassan Faghihi Nov 24 '16 at 14:47
  • @JonSkeet seem it wasn't :'( `java.lang.IllegalArgumentException: Unknown entity: hassan.personnel.managment.rests.WorksController$1` – Hassan Faghihi Nov 24 '16 at 17:34
33

Others have shown the "double brace" initializers, which I think should be avoided - this isn't what inheritance is for, and it will only work as shown when the fields are directly visible to subclasses, which I'd also argue against. It's not really the same thing as C# initializer blocks. It's a hack to take advantage of a language feature designed for other purposes.

If you have more values than you wish to pass to a constructor, you might want to consider using the builder pattern:

Person person = Person.newBuilder()
    .setFirstName("John")
    .setLastName("Doe")
    .setAddress(Address.newBuilder()
        .setStreet("...")
        .setCity("Phoenix")
        .build())
    .build();

This also allows you to make Person immutable. On the other hand, doing this requires the Person class to be designed for this purpose. That's nice for autogenerated classes (it's the pattern that Protocol Buffers follows) but is annoying boiler-plate for manually-written code.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    This sounds odd, but why not just chain the `set` functions by returning `this`? Then you could write `new Person().setFirstName("John").setLastName("Skeet")`. – ashes999 Dec 24 '13 at 03:14
  • 2
    @ashes999: You could do - but that would be pretty odd. (It also doesn't work with immutability, of course.) – Jon Skeet Dec 24 '13 at 09:52
  • That would be something like what C# calls a "Fluent interface," I think. I agree it would be odd, and a builder makes more sense. Thanks for the feedback. – ashes999 Dec 24 '13 at 15:11
  • 1
    There's another drawback to the 'return this' technique- setters on base classes return an object of the base type, making setters on subclasses inaccessible without casting. You can get round this by setting properties on subclasses first, but occasionally the order's important. This shouldn't matter with well written code, but that's obviously not always the case. – Flynn1179 Feb 18 '14 at 22:46
  • Curious what your `PersonBuilder` would look like. Are its properties a mirror image of `Person`? Is there any way this could be done without violating DRY principle? – wrschneider Nov 08 '15 at 02:31
  • @wrschneider: Yes, it would look something like Person, but with setters as well as getters. There's no real *logic* being repeated though. – Jon Skeet Nov 08 '15 at 07:49
  • Would you recommend having `Person.newBuilder()` return an object of an inner class `Person.Builder` which contains a private Person object and, being an inner class, has full access to its fields and thus it obviates the need to repeat the set of fields? – Klitos Kyriacou Feb 05 '16 at 12:11
  • The "Gang of Four" builder pattern is addressed in [another question](https://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns-in-javas-core-libraries/2707195#2707195), and another variant is explained in [this Oracle blog](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) – woodvi Apr 20 '22 at 18:03
5

Normally we use constructors in java to such cases

by using a constructor in the class which you want to create an object you can use that to pass the arguments at the object creating step, ex- MyData obj1 = new MyData("name",24);

for this case you have to use parameterized constructor matching to the arguments you pass from the main method

Ex-

MyData(String name, int age){
    this.name=name;
    this.age=age;
    }

The full code as follows

class MyData{
public String name;
public int age;

 MyData(String name, int age){
    this.name=name;
    this.age=age;
    }
     public static void main(String args[]){
        MyData obj1 = new MyData("name",24);

    }
}
Chamith Chathuka
  • 605
  • 1
  • 6
  • 18
  • they, in c# :)), also use them, but imagine we have 10+ fields... Now compare the readability of the old style vs C#: new MyData(new BigDecimal(24), new..., ...); new MyData{tax=new BigDecimal(24), amount=..., discount=...) – epox Jul 20 '19 at 21:34
5

Since double curly braces are generally avoided, you can create a very simple and generic sort of "builder" class that can set properties in a somewhat idiomatic way.

Note: I call the class "Bean" or POJO to follow the javabean standard: What is a JavaBean exactly?. I would primarily use this class to init javabeans anyway.

Bean.java

public class Bean<T> {
    private T object;
    public Bean(Supplier<T> supplier) { object = supplier.get(); }
    public Bean(T object) { this.object = object; }
    public T set(Consumer<T> setter) {
        setter.accept(object);
        return object;
    }
}

Instances of this Bean class can be created from an existing object or generated using a Supplier. The object is stored in the the field object. The set method is a higher-order function that takes in another function--Consumer<T>. Consumers take in one argument and return void. This will create the setter side-effects in a new scope.

The Bean .set(...) method returns object that can be used directly in an assignment.

I like this method because the object's assignment are contained within closed blocks and it feels like I'm setting properties before the object is created rather than than creating the object and mutating it.

The end result is a decent way to create new java objects but this is still a little wordy from the C# object initializer sigh.


And here is the class in use:

    // '{}' creates another scope so this function's scope is not "polluted"
    // '$' is used as the identifier simply because it's short
    Rectangle rectangle = new Bean<>(Rectangle::new).set($ -> {
        $.setLocation(0, 0);
        $.setBounds(0, 0, 0, 0);
        // set other properties
    });

if you have nested items, it might be a better to name the variables accordingly. Java doesn't let you use reuse $ because it exists in the outer scope and there is no shadowing.

    // this time we pass in new Rectangle() instead of a Supplier
    Rectangle rectangle3 = new Bean<>(new Rectangle()).set(rect-> {
        rect.setLocation(-50, -20);
        // setBounds overloads to take in another Rectangle
        rect.setBounds(new Bean<>(Rectangle::new).set(innerRect -> {
            innerRect.setLocation(0, 0);
            innerRect.setSize(new Bean<>(Dimension::new).set(dim -> {
                dim.setSize(640, 480);
            }));
        }));
    });

now compare the normal code

    // innerRect and dimension are part of the outer block's scope (bad)
    Rectangle rectangle4 = new Rectangle();
    rectangle4.setLocation(-50, -20);
    Rectangle innerRect = new Rectangle();
    innerRect.setLocation(0, 0);
    Dimension dimension = new Dimension();
    dimension.setSize(640, 480);
    innerRect.setSize(dimension);
    rectangle4.setBounds(innerRect);

Alternatively, you could have a lambda that takes in void and returns your object and cast it as a Supplier<DesiredType> and immediately invoke .get(). This doesn't require a separate class but you have to create bean yourself.

    Rectangle rectangle5 = ((Supplier<Rectangle>)() -> {
        Rectangle rect = new Rectangle();
        rect.setLocation(0, 0);
        return rect;
    }).get();

A note on practicality: Because you can't reuse $ when nesting elements, this method still tends to be a bit wordy. The variable names start getting long and the any syntax appeal goes away.

It can also be easy to abuse the set() method to create instance of objects within the closure. To use correctly, the only side affects should be on the object you're creating.

One more note: this is really just for fun. Don't ever use this in production.

Community
  • 1
  • 1
Rico Kahler
  • 17,616
  • 11
  • 59
  • 85
2

If your classes have constructors that takes values for the members, you can create the instance like this:

Person p = new Person("John", "Doe", new Address("1234 St.", "Phoenix"));

If not, you have to use the setter methods after object creation.

Person p = new Person();
p.setFirstName("John");
// and so on

Take a look at the official Java tutorial.

1

No, there isn't. There are some hacks and workarounds but Java does not have object initializers. The basic premise is... Use double brace initialization which syntactically looks similar but is not the same thing under the hood. Or create constructors that you can use to initialize the object (the old way). Or go nut job crazy and use design patterns like builder etc. to do something that is built into C#.

LordWabbit
  • 147
  • 5
1

You can do something similar in Java with a double brace initialization block:

Person p = new Person() {{
    firstName = "John";
    lastName = "Doe";
    address = new Address() {{
        street = "1234 St.";
        city = "Phoenix";
    }};
}};

However this is just using an initialization block inside an anonymous inner class so would be less efficient than constructing the objects in the normal way.

James Goodwin
  • 7,360
  • 5
  • 29
  • 41