Are C# style object initializers available in Java

Java

Java Problem Overview


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"
    }
};

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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.

Solution 3 - Java

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);
			
	}
}

Solution 4 - Java

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: https://stackoverflow.com/questions/3295496/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.

Solution 5 - Java

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.

Solution 6 - Java

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.

Solution 7 - Java

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#.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHaoView Question on Stackoverflow
Solution 1 - JavaTomasz NurkiewiczView Answer on Stackoverflow
Solution 2 - JavaJon SkeetView Answer on Stackoverflow
Solution 3 - JavaChamith ChathukaView Answer on Stackoverflow
Solution 4 - JavaRico KahlerView Answer on Stackoverflow
Solution 5 - Javauser647772View Answer on Stackoverflow
Solution 6 - JavaJames GoodwinView Answer on Stackoverflow
Solution 7 - JavaLordWabbitView Answer on Stackoverflow