The best Java idiom I've seem for simulating keyword arguments in constructors is the Builder pattern, described in Effective Java 2nd Edition.
The basic idea is to have a Builder class that has setters (but usually not getters) for the different constructor parameters. There's also a build() method. The Builder class is often a (static) nested class of the class that it's used to build. The outer class's constructor is often private.
The end result looks something like:
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();
The main caveats are:
- Setting up the pattern is pretty verbose (as you can see). Probably not worth it except for classes you plan on instantiating in many places.
- There's no compile-time checking that all of the parameters have been specified exactly once. You can add runtime checks, or you can use this only for optional parameters and make required parameters normal parameters to either Foo or the Builder's constructor. (People generally don't worry about the case where the same parameter is being set multiple times.)
You may also want to check out this blog post (not by me).
Answer from Laurence Gonsalves on Stack OverflowKeyword arguments for java? What do you think? - Stack Overflow
Named Parameters in Java
Can you use a concept similar to keyword args for python in Java to minimize the number of accessor methods? - Stack Overflow
What is the reason for not allowing named arguments for Java interop? - Language Design - Kotlin Discussions
The best Java idiom I've seem for simulating keyword arguments in constructors is the Builder pattern, described in Effective Java 2nd Edition.
The basic idea is to have a Builder class that has setters (but usually not getters) for the different constructor parameters. There's also a build() method. The Builder class is often a (static) nested class of the class that it's used to build. The outer class's constructor is often private.
The end result looks something like:
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();
The main caveats are:
- Setting up the pattern is pretty verbose (as you can see). Probably not worth it except for classes you plan on instantiating in many places.
- There's no compile-time checking that all of the parameters have been specified exactly once. You can add runtime checks, or you can use this only for optional parameters and make required parameters normal parameters to either Foo or the Builder's constructor. (People generally don't worry about the case where the same parameter is being set multiple times.)
You may also want to check out this blog post (not by me).
This is worth of mentioning:
Foo foo = new Foo() {{
color = red;
name = "Fred";
size = 42;
}};
the so called double-brace initializer. It is actually an anonymous class with instance initializer.
I have always wondered why we don't have this in Java and why there has never been a JEP proposing this.
Also Named parameters go hand in glove with default values, similar to how we have Annotation parameters.
So my primary ask is two things,
-
Do we think Named Parameters in Java is a good idea?
-
If yes, what's the challenge in adding them in a backward compatible manner.
Edit 1: Someone asked for an example. So here it goes (its oversimplified, not real code obviously)
Consider the below example
public class NamedParametersExample {
public Long calculateCost(String typeOfPackage, String typeOfCustomer, double additionalDiscount) {
return calculateCost(typeOfPackage, false, "regular", additionalDiscount);
}
public Long calculateCost(String typeOfPackage, String typeOfCustomer) {
return calculateCost(typeOfPackage, false, "regular", 0.0);
}
public Long calculateCost(String typeOfPackage) {
return calculateCost(typeOfPackage, false, "regular", 0.0);
}
public Long calculateCost(String typeOfPackage, boolean wantSameDayDelivery) {
return calculateCost(typeOfPackage, wantSameDayDelivery, "regular", 0.0);
}
public Long calculateCost(String typeOfPackage, boolean wantSameDayDelivery, double additionalDiscount) {
return calculateCost(typeOfPackage, wantSameDayDelivery, "regular", additionalDiscount);
}
public Long calculateCost(String typeOfPackage, boolean wantSameDayDelivery, String typeOfCustomer, double additionalDiscount) {
//Implementation
}
}If you write the same in Kotlin, it gets simplified to,
class NamedParametersKotlin {
fun calculateCost(
typeOfPackage: String,
wantSameDayDelivery: Boolean = false,
typeOfCustomer: String = "regular",
additionalDiscount: Double = 0.0
): Long {
//Real code
return 0L
}
}Which can then be invoked like,
fun callerExample() {
calculateCost(typeOfPackage = "Grocery", wantSameDayDelivery = true)
calculateCost(typeOfPackage = "HighValue", additionalDiscount = 0.3)
calculateCost(typeOfPackage = "Subscription", additionalDiscount = 0.3, typeOfCustomer = "subcriber")
}Edit 2: Stop reading this question as I am complaining about not having Named Parameters in Java or that I am saying "Kotlin Good, Java bad". I am genuinely curious the advantages/disadvantages of adding Named Parameters in Java. Also please don't reply, "just overload the method". That point of this question is not to know how we can continue to function without Named parameters.
Edit 3: Thanks everyone for your insightful comments. This is exactly what I was looking for and I now have good enough amount of material to read and follow up this weekend. :)
No there is no kwargs in java. Instead you can something similar to your function by using java varargs to save them as java properties.
You do you can something like this:
useKwargs("param1=value1","param2=value2");
Example code:
public void useKwargs(String... parameters) {
Properties properties = new Properties();
for (String param : parameters) {
String[] pair = parseKeyValue(param);
if (pair != null) {
properties.setProperty(pair[0], pair[1]);
}
}
doSomething(properties);
}
public void doSomething(Properties properties) {
/**
* Do something using using parameters specified in the properties
*/
}
private static String[] parseKeyValue(String token) {
if (token == null || token.equals("")) {
return null;
}
token = token.trim();
int index = token.indexOf("=");
if (index == -1) {
return new String[] { token.trim(), "" };
} else {
return new String[] { token.substring(0, index).trim(),
token.substring(index + 1).trim() };
}
}
Use that pattern if it suits and it fits best but it really should be an exception to the rule in Java - it will probably not be appropriate.
Best practice in Java is to use getter and setter methods for each variable. Yes it's more code - so what - if your lazy get your IDE to auto-generate them. It's there for a very good reason. Many good reasons. Some are;
- Promotes private variables
- Defines an external interface to other classes allowing the class to control what and how to set or get variables
- Promotes good coding practice by establishing a standard way to deal with object variables
The problem you'll encounter here by porting this pattern over is due to typing. Python is dynamically typed and Java is statically typed. So, in order to use the same pattern in Java, you will have to store the values in something like a string/object array and then return them like that as an object or as a String. then you'll have to convert them sometime later. Maybe if your 'properties' were all strings it would be okay. There are exceptions to the rule, but you need to know all of the rules in order to break them well. If they are different types (String, int, CustomObject etc.) don't use the same pattern you use in Python.