Related
I have a problem with enum in Java. I have an enum that starts from -1:
public enum AipType {
Unknown(-1),
None(0),
AipMod(1),
AipNoMod(2);
private final int id;
AipType(int id) {this.id = id;}
public int getValue() {return id;}
}
The problem is when I use this code to initialize a var of AipType
AipType at = AipType.getValues()[index];
where index is a number in the interval [-1,0,1,2] the -1 mess up the value.
i.e. 0 returns Unknown, 1 returns AipMod and 2 returns AipNoMod.
I used this implementation because I need to set manually the numeric value for each enum case. In other case I have a gap beetwen the values so I have the same problem: I cannot use values() and then access with [ ].
I tried to initialize in this way
AipType at = AipType(index);
but doesn't work.
Ideas ? Thanks...
We don't know what the getValues() method you're using exactly doing. Is it supposed to be values().
Anyway, you can always add a static method in your enum, which returns the correct enum instance for that value, and invoke it wherever you need it:
public enum AipType {
Unknown(-1),
None(0),
AipMod(1),
AipNoMod(2);
private final int id;
AipType(int id) {this.id = id;}
public int getValue() {return id;}
public static AipType fromValue(int id) {
for (AipType aip: values()) {
if (aip.getValue() == id) {
return aip;
}
}
return null;
}
}
If you're invoking fromValue() too often, you might also want to cache the array returned by values() inside the enum itself, and use it. Or even better, a map would be a better idea.
Enum.getValues() returns an array of the enums based on the definition order in the enum class.
getValues() doesn't know about the id field or the getValue() method you have added to your enum.
What you could do instead of calling getValues()[-1] (by the way, you'll never be able to index an array in Java with -1) is to add a static function like:
static AipType getAipType(int id) {
for (AipType a : getValues()) {
if (a.getId() == id) return a;
}
throw new IllegalArgumentException("id=" + id + " does not exist");
}
Just have a Map<Integer, AipType> instead of using values(), and expose access to it via a method:
public enum AipType {
UNKNOWN(-1),
NONE(0),
MOD(1),
NO_MOD(2);
private static final Map<Integer, AipType> VALUE_TO_ENUM_MAP;
private final int value;
static {
VALUE_TO_ENUM_MAP = new HashMap<>();
for (AipType type : EnumSet.allOf(AipType.class)) {
VALUE_TO_ENUM_MAP.put(type.value, type);
}
}
private AipType(int value) {
this.value = value;
}
public int getValue() {
return id;
}
public static AipType forValue(int value) {
return VALUE_TO_ENUM_MAP.get(value);
}
}
That will be completely flexible about values - or you could still use an array and just offset it appropriately.
Can you declare your enum like below?
public enum AipType {
Unknown(-1),None(0),AipMod(1),AipNoMod(2);
private int value;
private AipType(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
public static AipType fromValue(int value) {
for (AipType at: values()) {
if (at.getValue() == value) {
return at;
}
}
return null;
}
};
And instantiate like:
AipType at = AipType.fromValue(-1);
If the ids are completely custom, the only chance you'd have would be to create a map and store the id->AipType mapping there.
Example:
public enum AipType {
... //enum definitions here
static Map<Integer, AipType> map = new HashMap<>();
static {
for( AipType a : AipType.values() ) {
map.put(a.id, a);
}
}
public static AipType typeById( int id ) {
return map.get(id);
}
}
Then call it like AipType.typeById(-1);.
Suppose I have a Enum defined something like this:
public enum Sample{
// suppose AClass.getValue() returns an int
A(AClass.getValue()),
B(AClass.getValue()),
C(AClass.getValue());
private int _value;
private Sample(int _val){
this._value = _val;
}
public int getVal(){
return _value;
}
I can pull out values using Sample.A or Sample.A.getAVal() without issue.
Now suppose that AClass.getValue() could take a parameter to return a possibly different particular value, eg AClass.getValue(42).
It is possible to pass arguments to a public Enum method and retrive the Enum values? In other words, could I have an Enum definition like
public enum Sample{
// suppose AClass.getValue() returns an int
A(AClass.getAValue()),
B(AClass.getBValue()),
C(AClass.getCValue());
private int _value;
private Sample(int _val){
this._value = _val;
}
public int getVal(){
return _value;
}
public int getVal(int a){
// somehow pull out AClass.getAValue(a)
}
using Sample.A.getValue(42)?
You can do it, but only by making an abstract method in the enum, and overriding it in each value:
public enum Sample {
A(AClass.getAValue()) {
#Override public int getVal(int x) {
return AClass.getAValue(x);
}
},
B(BClass.getAValue()) {
#Override public int getVal(int x) {
return BClass.getBValue(x);
}
},
C(CClass.getAValue()) {
#Override public int getVal(int x) {
return CClass.getCValue(x);
}
};
private int _value;
private Sample(int _val){
this._value = _val;
}
public int getVal(){
return _value;
}
public abstract int getVal(int x);
}
Of course if you could create an instance of some other base type which has a getValue(int x) method, then you could put the code into the enum class itself instead of into the nested ones.
As stated in Java Specification
there is only one instance of each enum constant
So no, you can't have different values of a specific enum constant.
But you could put an array or a map inside your enum, so Sample.A.getValue(42) would return Sample.A.myMap.get(42) :
public enum Sample{
A(),
B(),
C();
Map<Integer, Integer> myMap = new HashMap<Integer, Integer>();
public int getVal(int i){
return myMap.get(i);
}
public int setVal(int i, int v){
return myMap.put(i, v);
}
}
public class App {
public static void main(String[] args) {
Fruit.setCounter(5);
System.out.println(Fruit.Apple.getCmd());
Fruit.setCounter(6);
System.out.println(Fruit.Apple.getCmd());
}
}
public enum Fruit {
Apple {
public String getCmd() {
return counter + " apples";
}
},
Banana {
public String getCmd() {
return counter + " bananas";
}
};
private static int counter = 0;
public abstract String getCmd();
public static void setCounter(int c) {
counter = c;
}
}
Output:
5 apples
6 apples
What is the best way to use the values stored in an Enum as String literals?
For example:
public enum Modes {
some-really-long-string,
mode1,
mode2,
mode3
}
Then later I could use Mode.mode1 to return its string representation as mode1. Without having to keep calling Mode.mode1.toString().
You can't. I think you have FOUR options here. All four offer a solution but with a slightly different approach...
Option One: use the built-in name() on an enum. This is perfectly fine if you don't need any special naming format.
String name = Modes.mode1.name(); // Returns the name of this enum constant, exactly as declared in its enum declaration.
Option Two: add overriding properties to your enums if you want more control
public enum Modes {
mode1 ("Fancy Mode 1"),
mode2 ("Fancy Mode 2"),
mode3 ("Fancy Mode 3");
private final String name;
private Modes(String s) {
name = s;
}
public boolean equalsName(String otherName) {
// (otherName == null) check is not needed because name.equals(null) returns false
return name.equals(otherName);
}
public String toString() {
return this.name;
}
}
Option Three: use static finals instead of enums:
public final class Modes {
public static final String MODE_1 = "Fancy Mode 1";
public static final String MODE_2 = "Fancy Mode 2";
public static final String MODE_3 = "Fancy Mode 3";
private Modes() { }
}
Option Four: interfaces have every field public, static and final:
public interface Modes {
String MODE_1 = "Fancy Mode 1";
String MODE_2 = "Fancy Mode 2";
String MODE_3 = "Fancy Mode 3";
}
Every enum has both a name() and a valueOf(String) method. The former returns the string name of the enum, and the latter gives the enum value whose name is the string. Is this like what you're looking for?
String name = Modes.mode1.name();
Modes mode = Modes.valueOf(name);
There's also a static valueOf(Class, String) on Enum itself, so you could also use:
Modes mode = Enum.valueOf(Modes.class, name);
You could override the toString() method for each enum value.
Example:
public enum Country {
DE {
#Override
public String toString() {
return "Germany";
}
},
IT {
#Override
public String toString() {
return "Italy";
}
},
US {
#Override
public String toString() {
return "United States";
}
}
}
Usage:
public static void main(String[] args) {
System.out.println(Country.DE); // Germany
System.out.println(Country.IT); // Italy
System.out.println(Country.US); // United States
}
As Benny Neugebauer mentions, you could overwrite the toString(). However instead overwriting the toString for each enum field I like more something like this:
public enum Country{
SPAIN("EspaƱa"),
ITALY("Italia"),
PORTUGAL("Portugal");
private String value;
Country(final String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public String toString() {
return this.getValue();
}
}
You could also add a static method to retrieve all the fields, to print them all, etc.
Simply call getValue to obtain the string associated to each Enum item
mode1.name() or String.valueOf(mode1). It doesn't get better than that, I'm afraid
public enum Modes {
MODE1("Mode1"),
MODE2("Mode2"),
MODE3("Mode3");
private String value;
public String getValue() {
return value;
}
private Modes(String value) {
this.value = value;
}
}
you can make a call like below wherever you want to get the value as a string from the enum.
Modes.MODE1.getvalue();
This will return "Mode1" as a String.
For my enums I don't really like to think of them being allocated with 1 String each. This is how I implement a toString() method on enums.
enum Animal
{
DOG, CAT, BIRD;
public String toString(){
switch (this) {
case DOG: return "Dog";
case CAT: return "Cat";
case BIRD: return "Bird";
}
return null;
}
}
You can use Mode.mode1.name() however you often don't need to do this.
Mode mode =
System.out.println("The mode is "+mode);
As far as I know, the only way to get the name would be
Mode.mode1.name();
If you really need it this way, however, you could do:
public enum Modes {
mode1 ("Mode1"),
mode2 ("Mode2"),
mode3 ("Mode3");
private String name;
private Modes(String s) {
name = s;
}
}
my solution for your problem!
import java.util.HashMap;
import java.util.Map;
public enum MapEnumSample {
Mustang("One of the fastest cars in the world!"),
Mercedes("One of the most beautiful cars in the world!"),
Ferrari("Ferrari or Mercedes, which one is the best?");
private final String description;
private static Map<String, String> enumMap;
private MapEnumSample(String description) {
this.description = description;
}
public String getEnumValue() {
return description;
}
public static String getEnumKey(String name) {
if (enumMap == null) {
initializeMap();
}
return enumMap.get(name);
}
private static Map<String, String> initializeMap() {
enumMap = new HashMap<String, String>();
for (MapEnumSample access : MapEnumSample.values()) {
enumMap.put(access.getEnumValue(), access.toString());
}
return enumMap;
}
public static void main(String[] args) {
// getting value from Description
System.out.println(MapEnumSample.getEnumKey("One of the fastest cars in the world!"));
// getting value from Constant
System.out.println(MapEnumSample.Mustang.getEnumValue());
System.out.println(MapEnumSample.getEnumKey("One of the most beautiful cars in the world!"));
System.out.println(MapEnumSample.Mercedes.getEnumValue());
// doesnt exist in Enum
System.out.println("Mustang or Mercedes, which one is the best?");
System.out.println(MapEnumSample.getEnumKey("Mustang or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
+ MapEnumSample.getEnumKey("Ferrari or Mustang, which one is the best?") + " is the best!.");
// exists in Enum
System.out.println("Ferrari or Mercedes, wich one is the best?");
System.out.println(MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
+ MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") + " is the best!");
}
}
You can simply use:
""+ Modes.mode1
public enum Environment
{
PROD("https://prod.domain.com:1088/"),
SIT("https://sit.domain.com:2019/"),
CIT("https://cit.domain.com:8080/"),
DEV("https://dev.domain.com:21323/");
private String url;
Environment(String envUrl) {
this.url = envUrl;
}
public String getUrl() {
return url;
}
}
String prodUrl = Environment.PROD.getUrl();
It will print:
https://prod.domain.com:1088/
This design for enum string constants works in most of the cases.
Enum is just a little bit special class. Enums can store additional fields, implement methods etc. For example
public enum Modes {
mode1('a'),
mode2('b'),
mode3('c'),
;
char c;
private Modes(char c) {
this.c = c;
}
public char character() {
return c;
}
}
Now you can say:
System.out.println(Modes.mode1.character())
and see output:
a
package com.common.test;
public enum Days {
monday(1,"Monday"),tuesday(2,"Tuesday"),wednesday(3,"Wednesday"),
thrusday(4,"Thrusday"),friday(5,"Friday"),saturday(6,"Saturday"),sunday(7,"Sunday");
private int id;
private String desc;
Days(int id,String desc){
this.id=id;
this.desc=desc;
}
public static String getDay(int id){
for (Days day : Days.values()) {
if (day.getId() == id) {
return day.getDesc();
}
}
return null;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
};
This method should work with any enum:
public enum MyEnum {
VALUE1,
VALUE2,
VALUE3;
public int getValue() {
return this.ordinal();
}
public static DataType forValue(int value) {
return values()[value];
}
public String toString() {
return forValue(getValue()).name();
}
}
i found this one is more easy for preventing type error:
public enum Modes {
some-really-long-string,
mode1,
mode2,
mode3;
String str;
Modes(){
this.str = super.name();
}
#Override
#NonNull
public String toString() {
return str;
}
however - this may work when you need to use a String on a log/println or whenever java compiles the toString() method automatically, but on a code line like this ->
// sample method that require (string,value)
intent.putExtra(Modes.mode1 ,shareElement.getMode()); // java error
// first argument enum does not return value
instead as mentioned above you will still have to extend the enum and use .name() in those cases like this:
intent.putExtra(Modes.mode1.name() ,shareElement.getMode());
after many tries I have come with this solution
public static enum Operation {
Addition, Subtraction, Multiplication, Division,;
public String getUserFriendlyString() {
if (this==Addition) {
return " + ";
} else if (this==Subtraction) {
return " - ";
} else if (this==Multiplication) {
return " * ";
} else if (this==Division) {
return " / ";
}
return "undefined";
}
}
You can try this:
public enum Modes {
some-really-long-string,
mode1,
mode2,
mode3;
public String toString(){
switch(this) {
case some-really-long-string:
return "some-really-long-string";
case mode2:
return "mode2";
default: return "undefined";
}
}
}
use mode1.name() or String.valueOf(Modes.mode1)
What is the correct way to cast an Int to an enum in Java given the following enum?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Try MyEnum.values()[x] where x must be 0 or 1, i.e. a valid ordinal for that enum.
Note that in Java enums actually are classes (and enum values thus are objects) and thus you can't cast an int or even Integer to an enum.
MyEnum.values()[x] is an expensive operation. If the performance is a concern, you may want to do something like this:
public enum MyEnum {
EnumValue1,
EnumValue2;
public static MyEnum fromInteger(int x) {
switch(x) {
case 0:
return EnumValue1;
case 1:
return EnumValue2;
}
return null;
}
}
If you want to give your integer values, you can use a structure like below
public enum A
{
B(0),
C(10),
None(11);
int id;
private A(int i){id = i;}
public int GetID(){return id;}
public boolean IsEmpty(){return this.equals(A.None);}
public boolean Compare(int i){return id == i;}
public static A GetValue(int _id)
{
A[] As = A.values();
for(int i = 0; i < As.length; i++)
{
if(As[i].Compare(_id))
return As[i];
}
return A.None;
}
}
You can try like this.
Create Class with element id.
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public static MyEnum fromId(int id) {
for (MyEnum type : values()) {
if (type.getId() == id) {
return type;
}
}
return null;
}
}
Now Fetch this Enum using id as int.
MyEnum myEnum = MyEnum.fromId(5);
I cache the values and create a simple static access method:
public static enum EnumAttributeType {
ENUM_1,
ENUM_2;
private static EnumAttributeType[] values = null;
public static EnumAttributeType fromInt(int i) {
if(EnumAttributeType.values == null) {
EnumAttributeType.values = EnumAttributeType.values();
}
return EnumAttributeType.values[i];
}
}
Java enums don't have the same kind of enum-to-int mapping that they do in C++.
That said, all enums have a values method that returns an array of possible enum values, so
MyEnum enumValue = MyEnum.values()[x];
should work. It's a little nasty and it might be better to not try and convert from ints to Enums (or vice versa) if possible.
This not something that is usually done, so I would reconsider. But having said that, the fundamental operations are: int --> enum using EnumType.values()[intNum], and enum --> int using enumInst.ordinal().
However, since any implementation of values() has no choice but to give you a copy of the array (java arrays are never read-only), you would be better served using an EnumMap to cache the enum --> int mapping.
Use MyEnum enumValue = MyEnum.values()[x];
Here's the solution I plan to go with. Not only does this work with non-sequential integers, but it should work with any other data type you may want to use as the underlying id for your enum values.
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static Map<Integer, MyEnum> buildMap() {
Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>();
MyEnum[] values = MyEnum.values();
for (MyEnum value : values) {
map.put(value.getId(), value);
}
return map;
}
}
I only need to convert id's to enums at specific times (when loading data from a file), so there's no reason for me to keep the Map in memory at all times. If you do need the map to be accessible at all times, you can always cache it as a static member of your Enum class.
In case it helps others, the option I prefer, which is not listed here, uses Guava's Maps functionality:
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static ImmutableMap<Integer, MyEnum> reverseLookup =
Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue);
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
}
With the default you can use null, you can throw IllegalArgumentException or your fromInt could return an Optional, whatever behavior you prefer.
Based on #ChadBefus 's answer and #shmosel comment, I'd recommend using this. (Efficient lookup, and works on pure java >= 8)
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Arrays;
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static Map<Integer, MyEnum> reverseLookup =
Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
public static void main(String[] args) {
System.out.println(fromInt(-66).toString());
}
}
You can iterate over values() of enum and compare integer value of enum with given id like below:
public enum TestEnum {
None(0),
Value1(1),
Value2(2),
Value3(3),
Value4(4),
Value5(5);
private final int value;
private TestEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static TestEnum getEnum(int value){
for (TestEnum e:TestEnum.values()) {
if(e.getValue() == value)
return e;
}
return TestEnum.None;//For values out of enum scope
}
}
And use just like this:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
I hope this helps ;)
Wrote this implementation. It allows for missing values, negative values and keeps code consistent. The map is cached as well. Uses an interface and needs Java 8.
Enum
public enum Command implements OrdinalEnum{
PRINT_FOO(-7),
PRINT_BAR(6),
PRINT_BAZ(4);
private int val;
private Command(int val){
this.val = val;
}
public int getVal(){
return val;
}
private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class);
public static Command from(int i){
return map.get(i);
}
}
Interface
public interface OrdinalEnum{
public int getVal();
#SuppressWarnings("unchecked")
static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){
Map<Integer, E> m = new HashMap<>();
for(Enum<E> e : EnumSet.allOf(clzz))
m.put(((OrdinalEnum)e).getVal(), (E)e);
return m;
}
}
In Kotlin:
enum class Status(val id: Int) {
NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5);
companion object {
private val statuses = Status.values().associateBy(Status::id)
fun getStatus(id: Int): Status? = statuses[id]
}
}
Usage:
val status = Status.getStatus(1)!!
A good option is to avoid conversion from int to enum: for example, if you need the maximal value, you may compare x.ordinal() to y.ordinal() and return x or y correspondingly. (You may need to re-order you values to make such comparison meaningful.)
If that is not possible, I would store MyEnum.values() into a static array.
This is the same answer as the doctors but it shows how to eliminate the problem with mutable arrays. If you use this kind of approach because of branch prediction first if will have very little to zero effect and whole code only calls mutable array values() function only once. As both variables are static they will not consume n * memory for every usage of this enumeration too.
private static boolean arrayCreated = false;
private static RFMsgType[] ArrayOfValues;
public static RFMsgType GetMsgTypeFromValue(int MessageID) {
if (arrayCreated == false) {
ArrayOfValues = RFMsgType.values();
}
for (int i = 0; i < ArrayOfValues.length; i++) {
if (ArrayOfValues[i].MessageIDValue == MessageID) {
return ArrayOfValues[i];
}
}
return RFMsgType.UNKNOWN;
}
enum MyEnum {
A(0),
B(1);
private final int value;
private MyEnum(int val) {this.value = value;}
private static final MyEnum[] values = MyEnum.values();//cache for optimization
public static final getMyEnum(int value) {
try {
return values[value];//OOB might get triggered
} catch (ArrayOutOfBoundsException e) {
} finally {
return myDefaultEnumValue;
}
}
}
How to implement Named Parameter idiom in Java? (especially for constructors)
I am looking for an Objective-C like syntax and not like the one used in JavaBeans.
A small code example would be fine.
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.
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
fix order of arguments
static check -> no nameless Person possible
hard to switch arguments of same type by accident (like it is possible in telescop constructors)
You could also try to follow advice from here.
int value;
int location;
boolean overwrite;
doIt(value=13, location=47, overwrite=true);
It's verbose on the call site, but overall gives the lowest overhead.
I would like to point out that this style addresses both the named parameter and the properties features without the get and set prefix which other language have. Its not conventional in Java realm but its simpler and shorter, especially if you have handled other languages.
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 Adane").age(3);
// addresses property style
System.out.println(jacobi.name());
System.out.println(jacobi.age());
// updates property values
jacobi.name("Lemuel Jacobi Adane");
jacobi.age(4);
System.out.println(jacobi.name());
System.out.println(jacobi.age());
}
}
If you are using Java 6, you can use the variable parameters and import static to produce a much better result. Details of this are found in:
http://zinzel.blogspot.com/2010/07/creating-methods-with-named-parameters.html
In short, you could 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));
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");
Java does not support Objective-C-like named parameters for constructors or method arguments. Furthermore, this is really not the Java way of doing things. In java, the typical pattern is verbosely named classes and members. Classes and variables should be nouns and method named should be verbs. I suppose you could get creative and deviate from the Java naming conventions and emulate the Objective-C paradigm in a hacky way but this wouldn't be particularly appreciated by the average Java developer charged with maintaining your code. When working in any language, it behooves you to stick to the conventions of the language and community, especially when working on a team.
I feel like the "comment-workaround" deserves it's own answer (hidden in existing answers and mentioned in comments here).
someMethod(/* width */ 1024, /* height */ 768);
You could use a 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;
}
}
Usage:
import static Something.*;
Something s = new Something(name("pen"), size(20), weight(8.2));
Limitations compared to real named parameters:
argument order is relevant
variable argument lists are not possible with a single constructor
you need a method for every argument
not really better than a comment (new Something(/*name*/ "pen", /*size*/ 20, /*weight*/ 8.2))
If you have the choice look at Scala 2.8. http://www.scala-lang.org/node/2075
Using Java 8's lambdas you can get even closer to real named parameters.
foo($ -> {$.foo = -10; $.bar = "hello"; $.array = new int[]{1, 2, 3, 4};});
Do note that this probably violates a couple dozen "java best practices" (like anything that makes use of the $ symbol).
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:
Considerably shorter than any builder pattern I've seen so far
Works for both methods and constructors
Completely type safe
It looks very close to actual named parameters in other programming languages
It's about as safe as your typical builder pattern (can set parameters multiple times)
Cons:
Your boss will probably lynch you for this
It's harder to tell what's going on
You can use project Lombok's #Builder annotation to simulate named parameters in Java. This will generate a builder for you which you can use to create new instances of any class (both classes you've written and those coming from external libraries).
This is how to enable it on a class:
#Getter
#Builder
public class User {
private final Long id;
private final String name;
}
Afterwards you can use this by:
User userInstance = User.builder()
.id(1L)
.name("joe")
.build();
If you'd like to create such a Builder for a class coming from a library, create an annotated static method like this:
class UserBuilder {
#Builder(builderMethodName = "builder")
public static LibraryUser newLibraryUser(Long id, String name) {
return new LibraryUser(id, name);
}
}
This will generate a method named "builder" which can be called by:
LibraryUser user = UserBuilder.builder()
.id(1L)
.name("joe")
.build();
This is a variant of the Builder Pattern as described by Lawrence above.
I find myself using this a lot (at the apropriate places).
The main difference is, that in this case the Builder is immuatable. This has the advantage that it can be reused and is thread-safe.
So you can use this to make one default Builder and then in the various places where you need it you can configure it and build your object.
This makes most sense, if you are building the same object over and over again, because then you can make the builder static and don't have to worry about changing it's settings.
On the other hand if you have to build objects with changing paramaters this has quiet some overhead. (but hey, you can combine static / dynamic generation with custom build methods)
Here is the example 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();
}
}
Any solution in Java is likely going to be pretty verbose, but it's worth mentioning that tools like Google AutoValues and Immutables will generate builder classes for you automatically using JDK compile time annotation processing.
For my case, I wanted named parameters to use in a Java enum, so a builder pattern wouldn't work because enum instances can't be instantiated by other classes. I came up with an approach similar #deamon's answer but adds compile-time checking of parameter ordering (at the expense of more code)
Here's client code:
Person p = new Person( age(16), weight(100), heightInches(65) );
And the 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; }
}
Here is a compiler-checked Builder pattern. Caveats:
this can't prevent double assignment of an argument
you can't have a nice .build() method
one generic parameter per field
So you need something outside the class that will fail if not passed Builder<Yes, Yes, Yes>. See the getSum static method as an example.
class No {}
class Yes {}
class Builder<K1, K2, K3> {
int arg1, arg2, arg3;
Builder() {}
static Builder<No, No, No> make() {
return new Builder<No, No, No>();
}
#SuppressWarnings("unchecked")
Builder<Yes, K2, K3> arg1(int val) {
arg1 = val;
return (Builder<Yes, K2, K3>) this;
}
#SuppressWarnings("unchecked")
Builder<K1, Yes, K3> arg2(int val) {
arg2 = val;
return (Builder<K1, Yes, K3>) this;
}
#SuppressWarnings("unchecked")
Builder<K1, K2, Yes> arg3(int val) {
this.arg3 = val;
return (Builder<K1, K2, Yes>) this;
}
static int getSum(Builder<Yes, Yes, Yes> build) {
return build.arg1 + build.arg2 + build.arg3;
}
public static void main(String[] args) {
// Compiles!
int v1 = getSum(make().arg1(44).arg3(22).arg2(11));
// Builder.java:40: error: incompatible types:
// Builder<Yes,No,Yes> cannot be converted to Builder<Yes,Yes,Yes>
int v2 = getSum(make().arg1(44).arg3(22));
System.out.println("Got: " + v1 + " and " + v2);
}
}
Caveats explained. Why no build method? The trouble is that it's going to be in the Builder class, and it will be parameterized with K1, K2, K3, etc. As the method itself has to compile, everything it calls must compile. So, generally, we can't put a compilation test in a method of the class itself.
For a similar reason, we can't prevent double assignment using a builder model.
The idiom supported by the karg library may be 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");
}
}
You can imitate named parameters applying this pattern:
public static class CarParameters {
// to make it shorter getters and props are omitted
public ModelParameter setName(String name) {
this.name = name;
return new ModelParameter();
}
public class ModelParameter {
public PriceParameter setModel(String model) {
CarParameters.this.model = model;
return new PriceParameter();
}
}
public class PriceParameter {
public YearParameter setPrice(double price) {
CarParameters.this.price = price;
return new YearParameter();
}
}
public class YearParameter {
public ColorParameter setYear(int year) {
CarParameters.this.year = year;
return new ColorParameter();
}
}
public class ColorParameter {
public CarParameters setColor(Color color) {
CarParameters.this.color = color;
return new CarParameters();
}
}
}
and then you can pass it to your method as this:
factory.create(new CarParameters()
.setName("Ford")
.setModel("Focus")
.setPrice(20000)
.setYear(2011)
.setColor(BLUE));
You can read more here https://medium.com/#ivorobioff/named-parameters-in-java-9072862cfc8c
Now that we're all on Java 17 ;-), using records is a super-easy way to imitate this idiom:
public class OrderTemplate() {
private int tradeSize, limitDistance, backoffDistance;
public record TradeSize( int value ) {}
public record LimitDistance( int value ) {}
public record BackoffDistance( int value ) {}
public OrderTemplate( TradeSize t, LimitDistance d, BackoffDistance b ) {
this.tradeSize = t.value();
this.limitDistance = d.value();
this.backoffDistance = b.value();
}
}
Then you can call:
var t = new OrderTemplate( new TradeSize(30), new LimitDistance(182), new BackoffDistance(85) );
Which I've found extremely easy to read and I've completely stopped getting all the int parameters mixed up ("was it size first or distance...").
package org.xxx.lang;
/**
* A hack to work around the fact that java does not support
* named parameters in function calls.
*
* Its easy to swap a few String parameters, for example.
* Some IDEs are better than others than showing the parameter names.
* This will enforce a compiler error on an inadvertent swap.
*
* #param <T>
*/
public class Datum<T> {
public final T v;
public Datum(T v) {
this.v = v;
}
public T v() {
return v;
}
public T value() {
return v;
}
public String toString() {
return v.toString();
}
}
Example
class Catalog extends Datum<String> {
public Catalog(String v) {
super(v);
}
}
class Schema extends Datum<String> {
public Schema(String v) {
super(v);
}
}
class Meta {
public void getTables(String catalog, String schema, String tablePattern) {
// pseudo DatabaseMetaData.getTables();
}
}
class MetaChecked {
public void getTables(Catalog catalog, Schema schema, String tablePattern) {
// pseudo DatabaseMetaData.getTables();
}
}
#Test
public void test() {
Catalog c = new Catalog("test");
assertEquals("test",c.v);
assertEquals("test",c.v());
assertEquals("test",c.value());
String t = c.v;
assertEquals("test",t);
}
public void uncheckedExample() {
new Meta().getTables("schema","catalog","%");
new Meta().getTables("catalog","schema","%"); // ooops
}
public void checkedExample() {
// new MetaChecked().getTables(new Schema("schema"),new Catalog("catalog"),"%"); // won't compile
new MetaChecked().getTables(new Catalog("catalog"), new Schema("schema"),"%");
}
maybe can use this:
HashMapFlow<String,Object> args2 = HashMapFlow.of( "name", "Aton", "age", 21 );
Integer age = args2.get("age",51);
System.out.println(args2.get("name"));
System.out.println(age);
System.out.println((Integer)args2.get("dayOfBirth",26));
class:
import java.util.HashMap;
public class HashMapFlow<K,V> extends HashMap {
public static <K, V> HashMapFlow<K, V> of(Object... args) {
HashMapFlow<K, V> map = new HashMapFlow();
for( int i = 0; i < args.length; i+=2) {
map.put((K)args[i], (V)args[i+1]);
}
return map;
}
public <T> T get(Object key, V defaultValue) {
V result = (V)get(key);
if( result == null ) {
result = defaultValue;
}
return (T)result;
}
public HashMapFlow add(K key, V value) {
put(key,value);
return this;
}
}
#irreputable came up with a nice solution. However - it might leave your Class instance in a invalid state, as no validation and consistency checking will happen. Hence I prefer to combine this with the Builder solution, avoiding the extra subclass to be created, although it would still subclass the builder class. Additionally, because the extra builder class makes it more verbose, I added one more method using a lambda. I added some of the other builder approaches for completeness.
Starting with a class as follows:
public class Foo {
static public class Builder {
public int size;
public Color color;
public String name;
public Builder() { size = 0; color = Color.RED; name = null; }
private Builder self() { return this; }
public Builder size(int size) {this.size = size; return self();}
public Builder color(Color color) {this.color = color; return self();}
public Builder name(String name) {this.name = name; return self();}
public Foo build() {return new Foo(this);}
}
private final int size;
private final Color color;
private final String name;
public Foo(Builder b) {
this.size = b.size;
this.color = b.color;
this.name = b.name;
}
public Foo(java.util.function.Consumer<Builder> bc) {
Builder b = new Builder();
bc.accept(b);
this.size = b.size;
this.color = b.color;
this.name = b.name;
}
static public Builder with() {
return new Builder();
}
public int getSize() { return this.size; }
public Color getColor() { return this.color; }
public String getName() { return this.name; }
}
Then using this applying the different methods:
Foo m1 = new Foo(
new Foo.Builder ()
.size(1)
.color(BLUE)
.name("Fred")
);
Foo m2 = new Foo.Builder()
.size(1)
.color(BLUE)
.name("Fred")
.build();
Foo m3 = Foo.with()
.size(1)
.color(BLUE)
.name("Fred")
.build();
Foo m4 = new Foo(
new Foo.Builder() {{
size = 1;
color = BLUE;
name = "Fred";
}}
);
Foo m5 = new Foo(
(b)->{
b.size = 1;
b.color = BLUE;
b.name = "Fred";
}
);
It looks like in part a total rip-off from what #LaurenceGonsalves already posted, but you will see the small difference in convention chosen.
I am wonder, if JLS would ever implement named parameters, how they would do it? Would they be extending on one of the existing idioms by providing a short-form support for it? Also how does Scala support named parameters?
Hmmm - enough to research, and maybe a new question.