Named parameter idioms in Java

How to implement a named named parameter in Java? (especially for designers)

I am looking for Objective-C syntax, not the one used in JavaBeans.

A small code example will be fine.

Thank.

+48
java idioms
Jan 01 '09 at 6:18
source share
14 answers

The best Java idiom that I think is for modeling keyword arguments in constructors is the Builder template described in Effective Java 2nd Edition .

The main idea is to have a Builder class that has setters (but usually not getters) for different constructor parameters. There is also a build() method. The Builder class is often the (static) nested class class that it used to build. The constructor of the outer class is often private.

The end result looks something like this:

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

To create an instance of Foo, you then write something like:

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

Key reservations:

  • Setting up the template is pretty verbose (as you can see). This is probably not worth it, except for the classes you plan to create in many places.
  • There is no compilation time check when all parameters have been specified exactly once. You can add runtime checks at run time, or use this only for optional parameters, as well as for normal parameters of the required parameters for Foo or the Builder constructor. (People usually don't worry about the same parameter being set multiple times.)

You can also check out this blog post (not me).

+69
Jan 01 '09 at 6:32
source share
โ€” -

It is worth mentioning:

 Foo foo = new Foo() {{ color = red; name = "Fred"; size = 42; }}; 

the so-called initializer with double binding. This is actually an anonymous class with an instance initializer.

+54
Jan 01 '09 at 9:59
source share

You can also try following the advice: http://www.artima.com/weblogs/viewpost.jsp?thread=118828

 int value; int location; boolean overwrite; doIt(value=13, location=47, overwrite=true); 

It is verbose on a call site, but overall provides the least cost.

+12
Mar 05 2018-12-17T00:
source share

Java 8 style:

 public class Person { String name; int age; private Person(String name, int age) { this.name = name; this.age = age; } static PersonWaitingForName create() { return name -> age -> new Person(name, age); } static interface PersonWaitingForName { PersonWaitingForAge name(String name); } static interface PersonWaitingForAge { Person age(int age); } public static void main(String[] args) { Person charlotte = Person.create() .name("Charlotte") .age(25); } } 
  • Named Parameters
  • set the order of arguments
  • static check โ†’ no name possible
  • it is difficult to switch arguments of the same type randomly (as is possible in telescope designers)
+9
Jul 23 '15 at 15:07
source share

If you use Java 6, you can use variable parameters and import static data to get a much better result. Details on this can be found in:

http://zinzel.blogspot.com/2010/07/creating-methods-with-named-parameters.html

In short, you might have something like:

 go(); go(min(0)); go(min(0), max(100)); go(max(100), min(0)); go(prompt("Enter a value"), min(0), max(100)); 
+8
Dec 08 2018-10-12T00:
source share

Here's a little variation on the technique given in Joshua Bloch Effective Java. Here I tried to make the client code more readable (or maybe more DSLish).

 /** * Actual class for which we want to implement a * named-parameter pseudo-constructor */ class Window{ protected int x, y, width, height; protected boolean isResizable; protected String title; public void show(){ // Show the window System.out.printf("Window \"%s\" set visible.%n",title); } /** * This class is only used to set the parameter values */ static class HavingProperties extends Window{ public HavingProperties x(int value){ this.x=value; return this; } public HavingProperties y(int value){ this.y=value; return this; } public HavingProperties width(int value){ this.width=value; return this; } public HavingProperties height(int value){ this.height=value; return this; } public HavingProperties resizable(boolean value){ this.isResizable=value; return this; } public HavingProperties title(String value){ this.title=value; return this; } } } public class NamedParameterIdiomInAction { public static void main(String... args){ Window window=new Window.HavingProperties().x(10).y(10).width(100). height(100).resizable(true).title("My App"); window.show(); } } 

Note that with this option, you can also give meaningful names to your pseudo-constructors.

+7
Jan 01 '09 at 21:31
source share

Java does not support Objective-C-named parameters for constructors or method arguments. Also, this is actually not a Java way to do something. In java, a typical template contains verbose classes and members. Classes and variables must be nouns, and the method name must be a verb. I assume that you can be creative and deviate from the Java naming conventions and emulate the Objective-C paradigm in a hacker way, but this will not be particularly useful to the average Java developer who is tasked with supporting your code. When working in any language, you should adhere to the conventions of the language and community, especially when working in a team.

+6
Jan 01 '09 at 6:36
source share

What about

 public class Tiger { String myColor; int myLegs; public Tiger color(String s) { myColor = s; return this; } public Tiger legs(int i) { myLegs = i; return this; } } Tiger t = new Tiger().legs(4).color("striped"); 
+5
Mar 24 2018-11-11T00:
source share

You can use the usual constructor and static methods that give the arguments a name:

 public class Something { String name; int size; float weight; public Something(String name, int size, float weight) { this.name = name; this.size = size; this.weight = weight; } public static String name(String name) { return name; } public static int size(int size) { return size; } public float weight(float weight) { return weight; } } 

Using:

 import static Something.*; Something s = new Something(name("pen"), size(20), weight(8.2)); 

Limitations compared to real named parameters:

  • argument argument is relevant
  • variable argument lists are not possible with a single constructor
  • you need a method for each argument
  • no better than comment (new Something ( /*name*/ "pen", /*size*/ 20, /*weight*/ 8.2) )

If you have a choice, check out Scala 2.8. http://www.scala-lang.org/node/2075

+2
Jan 01 '09 at 10:22
source share

I would like to point out that this style uses both a named parameter and properties without get and which has a different language. It is not ordinary in the Java sphere, but it is simpler, not difficult to understand, especially if you studied other languages.

 public class Person { String name; int age; // name property // getter public String name() { return name; } // setter public Person name(String val) { name = val; return this; } // age property // getter public int age() { return age; } // setter public Person age(int val) { age = val; return this; } public static void main(String[] args) { // Addresses named parameter Person jacobi = new Person().name("Jacobi").age(3); // Addresses property style System.out.println(jacobi.name()); System.out.println(jacobi.age()); //... jacobi.name("Lemuel Jacobi"); jacobi.age(4); System.out.println(jacobi.name()); System.out.println(jacobi.age()); } } 
+2
Nov 22 '15 at 8:50
source share

The idiom maintained by the karg library is worth considering:

 class Example { private static final Keyword<String> GREETING = Keyword.newKeyword(); private static final Keyword<String> NAME = Keyword.newKeyword(); public void greet(KeywordArgument...argArray) { KeywordArguments args = KeywordArguments.of(argArray); String greeting = GREETING.from(args, "Hello"); String name = NAME.from(args, "World"); System.out.println(String.format("%s, %s!", greeting, name)); } public void sayHello() { greet(); } public void sayGoodbye() { greet(GREETING.of("Goodbye"); } public void campItUp() { greet(NAME.of("Sailor"); } } 
+1
Feb 13 '12 at 17:18
source share

This is a variant of the Builder template described by Lawrence above.

I use this a lot (in suitable places).

The main difference is that in this case the Builder is immuatable. This has the advantage of being reusable and thread safe.

So, you can use this to create one default Builder, and then in different places where you need it, you can customize it and build your object.

It makes sense if you build the same object over and over again, because then you can make a static builder and not worry about changing it.

On the other hand, if you need to create objects with variable parameters, this calms some costs a bit. (but hey, you can combine static / dynamic generation with custom build methods)

Here is a sample code:

 public class Car { public enum Color { white, red, green, blue, black }; private final String brand; private final String name; private final Color color; private final int speed; private Car( CarBuilder builder ){ this.brand = builder.brand; this.color = builder.color; this.speed = builder.speed; this.name = builder.name; } public static CarBuilder with() { return DEFAULT; } private static final CarBuilder DEFAULT = new CarBuilder( null, null, Color.white, 130 ); public static class CarBuilder { final String brand; final String name; final Color color; final int speed; private CarBuilder( String brand, String name, Color color, int speed ) { this.brand = brand; this.name = name; this.color = color; this.speed = speed; } public CarBuilder brand( String newBrand ) { return new CarBuilder( newBrand, name, color, speed ); } public CarBuilder name( String newName ) { return new CarBuilder( brand, newName, color, speed ); } public CarBuilder color( Color newColor ) { return new CarBuilder( brand, name, newColor, speed ); } public CarBuilder speed( int newSpeed ) { return new CarBuilder( brand, name, color, newSpeed ); } public Car build() { return new Car( this ); } } public static void main( String [] args ) { Car porsche = Car.with() .brand( "Porsche" ) .name( "Carrera" ) .color( Color.red ) .speed( 270 ) .build() ; // -- or with one default builder CarBuilder ASSEMBLY_LINE = Car.with() .brand( "Jeep" ) .name( "Cherokee" ) .color( Color.green ) .speed( 180 ) ; for( ;; ) ASSEMBLY_LINE.build(); // -- or with custom default builder: CarBuilder MERCEDES = Car.with() .brand( "Mercedes" ) .color( Color.black ) ; Car c230 = MERCEDES.name( "C230" ).speed( 180 ).build(), clk = MERCEDES.name( "CLK" ).speed( 240 ).build(); } } 
0
Sep 16 '15 at 18:33
source share

Using Java 8 lambdas, you can get closer to real named parameters.

 foo($ -> {$.foo = -10; $.bar = "hello"; $.array = new int[]{1, 2, 3, 4};}); 

Note that this probably violates a couple of dozen โ€œbest Java practicesโ€ (for example, anything that uses the $ character).

 public class Main { public static void main(String[] args) { // Usage foo($ -> {$.foo = -10; $.bar = "hello"; $.array = new int[]{1, 2, 3, 4};}); // Compare to roughly "equivalent" python call // foo(foo = -10, bar = "hello", array = [1, 2, 3, 4]) } // Your parameter holder public static class $foo { private $foo() {} public int foo = 2; public String bar = "test"; public int[] array = new int[]{}; } // Some boilerplate logic public static void foo(Consumer<$foo> c) { $foo foo = new $foo(); c.accept(foo); foo_impl(foo); } // Method with named parameters private static void foo_impl($foo par) { // Do something with your parameters System.out.println("foo: " + par.foo + ", bar: " + par.bar + ", array: " + Arrays.toString(par.array)); } } 

Pros:

  • Significantly shorter than any builder pattern I've seen so far.
  • Works for both methods and designers.
  • Totally safe type
  • It looks very close to the actual named parameters in other programming languages.
  • This is about as safe as your typical builder pattern (can set parameters several times)

Minuses:

  • Your boss will probably lynch you for it.
  • Harder to say what's going on
0
Aug 14 '16 at 16:19
source share

Any solution in Java is likely to be pretty verbose, but it's worth mentioning that tools like Google AutoValues โ€‹โ€‹and Immutables will generate constructor classes to automatically use JDK compilation annotation processing.

In my case, I wanted named parameters to be used in the Java enum, so the linker pattern did not work because enum instances could not be created by other classes. I came up with an approach similar to @deamon, but adds a check on the time of ordering the parameters (due to more code) at compile time

Here's the client code:

 Person p = new Person( age(16), weight(100), heightInches(65) ); 

And implementation:

 class Person { static class TypedContainer<T> { T val; TypedContainer(T val) { this.val = val; } } static Age age(int age) { return new Age(age); } static class Age extends TypedContainer<Integer> { Age(Integer age) { super(age); } } static Weight weight(int weight) { return new Weight(weight); } static class Weight extends TypedContainer<Integer> { Weight(Integer weight) { super(weight); } } static Height heightInches(int height) { return new Height(height); } static class Height extends TypedContainer<Integer> { Height(Integer height) { super(height); } } private final int age; private final int weight; private final int height; Person(Age age, Weight weight, Height height) { this.age = age.val; this.weight = weight.val; this.height = height.val; } public int getAge() { return age; } public int getWeight() { return weight; } public int getHeight() { return height; } } 
0
Dec 21 '17 at 1:49 on
source share



All Articles