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.
Related
I am trying to make a list of objects that are all of an abstract class, but each are there own class. This list needs to persistent so I figured I implement parcelable since I have done so in the past. Only not with different classes all of an abstract class.
I tried just making the abstract class parcelable but that can't have a creator that I am used to because (of course) you can't create an instance of it (because it is abstract). Reading around I noticed that people said you dont need a constructor in the abstract class, just in the subclasses.
AbstractFocusPower class
public abstract class AbstractFocusPower implements Parcelable {
private transient AppExtension app;
private ImplementSchool school;
private String name;
private int duration;
private int cost;
private int altCost;
private int requiredLevel;
private boolean isSelected;
private boolean isResonant;
private int nofSpirtBonusUsed;
/**
* Constructor for Focus Power with no alternative cost
*/
public AbstractFocusPower(AppExtension app, ImplementSchool school, String name, int requiredLevel, int duration, int cost, boolean isSelected) {
this.app = app;
this.school = school;
this.name = name;
this.requiredLevel = requiredLevel;
this.duration = duration;
this.cost = cost;
this.altCost = -1;
this.isSelected = isSelected;
this.isResonant = false;
}
// I cut out the other constructors
public abstract AbstractFocusPower makeCopy();
public abstract String getDescription();
// I cut out the getters and setters
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.school == null ? -1 : this.school.ordinal());
dest.writeString(this.name);
dest.writeInt(this.duration);
dest.writeInt(this.cost);
dest.writeInt(this.altCost);
dest.writeInt(this.requiredLevel);
dest.writeByte(this.isSelected ? (byte) 1 : (byte) 0);
dest.writeByte(this.isResonant ? (byte) 1 : (byte) 0);
dest.writeInt(this.nofSpirtBonusUsed);
}
protected AbstractFocusPower(Parcel in) {
int tmpSchool = in.readInt();
this.school = tmpSchool == -1 ? null : ImplementSchool.values()[tmpSchool];
this.name = in.readString();
this.duration = in.readInt();
this.cost = in.readInt();
this.altCost = in.readInt();
this.requiredLevel = in.readInt();
this.isSelected = in.readByte() != 0;
this.isResonant = in.readByte() != 0;
this.nofSpirtBonusUsed = in.readInt();
}
Sample subclass
public class AegisFocusPower extends AbstractFocusPower {
public AegisFocusPower(AppExtension app) {
super(app, ImplementSchool.ABJURATION, app.getString(R.string.focus_power_name_aegis), 0, 1, 1, false);
}
#Override
public String getDescription() {
return getApp().getString(R.string.focus_power_desc_aegis, (1+((int) Math.floor(getApp().getCurrentCharacter().getOccultistLevel()/6.0))));
}
#Override
public AegisFocusPower makeCopy() {
return new AegisFocusPower(getApp());
}
public AegisFocusPower(Parcel in) {
super(in);
}
public static final Parcelable.Creator<AegisFocusPower> CREATOR = new Parcelable.Creator<AegisFocusPower>() {
public AegisFocusPower createFromParcel(Parcel in) {
return new AegisFocusPower (in);
}
public AegisFocusPower [] newArray(int size) {
return new AegisFocusPower[size];
}
};
}
Code where I use it
Gson gsonFocusPowers = new Gson();
String jsonFocusPowers = sharedPreferences.getString(FOCUS_POWERS_GSON, null);
Type typeFocusPower = new TypeToken<ArrayList<AbstractFocusPower>>() {
}.getType();
ArrayList<AbstractFocusPower> focusPowers;
focusPowers = gsonFocusPowers.fromJson(jsonFocusPowers, typeFocusPower);
if (focusPowers != null) {
this.focusPowers.addAll(checkForNewFocusPowers(focusPowers));
} else {
this.focusPowers = getNewFocusPowerList();
}
Unfortunately this gives me an error which I don't know how to fix.
java.lang.RuntimeException: Unable to create application nl.rekijan.occultistmentalfocushelper.AppExtension: java.lang.RuntimeException: Unable to invoke no-args constructor for class nl.rekijan.occultistmentalfocushelper.mvc.focuspowers.AbstractFocusPower. Registering an InstanceCreator with Gson for this type may fix this problem.
Edit: Not sure why that post is a duplicate. For starters it doesn't have an accepted answer. The answer requires a 3rd party library. The question isn't about multiple subclasses under a single abstract.
have you tried registering a type adapter, something like Using Gson and Abstract Classes ? I always add adapters both for specific formatting (for dates, big decimals, anything where you usually require a very specific format) but also for sub-classing.
In this case however, no adapter is needed, this is.. straight on?
public abstract class AbstractFocusPower implements Parcelable {
// just some property needed to be pushed through a constructor
protected final String myString;
protected AbstractFocusPower(String myString) {
this.myString = myString;
}
}
and then the impl (yeah added toString(), hashCode() and equals() the way I like them to be in domain objects..):
public class AegisFocusPower extends AbstractFocusPower {
boolean imParcelled;
public AegisFocusPower(String myString) {
super(myString);
}
#Override //yup the interface impl
public void parcelMe() {
imParcelled = true;
}
#Override
public String toString() {
return new StringBuilder("{ imParcelled : ").append(imParcelled).append(", myString : ").append(myString).append(" }").toString();
}
#Override
public int hashCode() {
return toString().hashCode();
}
#Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other == null || !(other instanceof AegisFocusPower)) {
return false;
} else {
return other.hashCode() == hashCode();
}
}
}
and then I can run the following junit :
#Test
public void AegisFocusPowerToJsonAndBack(){
// single instance
AegisFocusPower ea = new AegisFocusPower("apa");
String json = GSON.toJson(ea);
assertEquals("{\"imParcelled\":\"false\",\"myString\":\"apa\"}", json);
AegisFocusPower backAtYa = (AegisFocusPower) GSON.fromJson(json, AegisFocusPower.class);
assertEquals(backAtYa, ea);
// A list
AegisFocusPower ea2 = new AegisFocusPower("bepa");
AegisFocusPower ea3 = new AegisFocusPower("cepa");
List<AegisFocusPower> powerList = new ArrayList<>();
powerList.add(ea2);
powerList.add(ea3);
String jsonList = GSON.toJson(powerList);
assertEquals("[{\"imParcelled\":\"false\",\"myString\":\"bepa\"},{\"imParcelled\":\"false\",\"myString\":\"cepa\"}]", jsonList);
List<AegisFocusPower> backAtYaz = Arrays.asList(GSON.fromJson(jsonList,AegisFocusPower[].class));
assertEquals(backAtYaz.get(0), ea2);
assertEquals(backAtYaz.get(1), ea3);
}
whereas GSON is initialized simply like
private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(Boolean.class, new JsonBooleanDeAndSerializer()).create();
and the type adapter registered for booleans which I use is irrelevant for your problem.
This is.. simple enough and would work for you too?
Check your imports. You may have mistakenly imported wrong class in your pojo. i.e. I have imported android.net.TransportInfo instead of my own TransportInfo class
I am trying to model a train with a Java program.
Currently I have four classes:
Train,
BoxCar,
Cargo,
Person.
The BoxCar class has an array of Person and an array of Cargo. A BoxCar can only hold one type so when that type is given from the constructor,
I decide which array to use (either the people array or the cargo array). The thing is, I'd like to make that array inside BoxCar "generic" so that if there is another "kind" of type the user wants to use, it can be easily set.
They wouldn't need to declare another array inside the BoxCar class for that type and change the rest of the code.
How would I do this? I looked up Generic and Reflection but the examples I saw weren't exactly for my scenario and I'm learning this for the first time.
Can someone map out the right approach to take?
BoxCar:
class BoxCar {
String boxType;
int boxID;
int count;
boolean isEmpty;
Cargo cargo[];
Person people[];
int capacity;
BoxCar(String box_type, int ID, int cap) {
boxType = box_type;
boxID = ID;
isEmpty = true;
count = 0;
capacity = cap;
}
}
Person:
class Person {
String government_ID, name;
int age;
Person(String gov_ID, String Name, int Age) {
government_ID = gov_ID;
name = Name;
age = Age;
}
}
Cargo:
class Cargo {
String cargo_ID;
int height, weight;
Cargo(String c_id, int w, int h) {
cargo_ID = c_id;
height = h;
weight = w;
}
}
Maybe this helps you out
public class Train {
public static void main(String[] args) {
new Train();
}
public Train() {
List<Person> persons = new ArrayList<>();
persons.add(new Person("foo", "bar"));
BoxCar<Person> personBoxCar = new BoxCar<>(persons);
List<Cargo> cargo = new ArrayList<>();
cargo.add(new Cargo("test"));
BoxCar<Cargo> cargoBoxCar = new BoxCar<>(cargo);
}}
public class Person {
private String name;
private String surname;
public Person(String name, String surname) {
this.name = name;
this.surname = surname;
}
public String getName() {
return name;
}
public String getSurname() {
return surname;
}}
public class Cargo {
private String cargoType;
public Cargo(String cargoType) {
this.cargoType = cargoType;
}
public String getCargoType() {
return cargoType;
}}
public class BoxCar<T> {
private List<T> myArray;
public BoxCar(List<T> myArray) {
this.myArray = myArray;
}}
The best way to accomplish that is using generics.
Generics are a facility of generic programming that were added to the Java programming language in 2004 within version J2SE 5.0. They were designed to extend Java's type system to allow “a type or method to operate on objects of various types while providing compile-time type safety”
https://en.wikipedia.org/wiki/Generics_in_Java
The generic E allows passing a type according to your needs.
class BoxCar<E> {
private int boxID;
private int count;
private boolean isEmpty;
private E target[];
private int capacity;
public BoxCar(int ID, int cap) {
boxID = ID;
isEmpty = true;
count = 0;
capacity = cap;
}
public setTarget(E target[]) {
thid.target = target;
}
}
Another approach is to use interfaces, for example this could be a solution:
Implementing an interface allows a class to become more formal about the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.
https://docs.oracle.com/javase/tutorial/java/concepts/interface.html
import java.util.HashMap;
import java.util.Map;
public class A {
public static void main(String[] args) {
BoxCar<String, String> boxCar_1 = new BoxCar<>(new Person("gov_id", "name", 35), 1, 1);
BoxCar<String, String> boxCar_2 = new BoxCar<>(new Cargo("c_id", 1, 1), 1, 1);
}
}
/**
* This interface declares the
* methods for box targets.
*
* #param <T> for jey
* #param <E> for value
*/
interface BoxCarTarget<T, E> {
/**
* This method returns the data regarding to
* a specific BoxCar target.
*
* #return Map with specific data.
*/
Map<T, E> getPayload();
}
class BoxCar<T, E> {
private BoxCarTarget<T, E> target;
private int boxID;
private int count;
private boolean isEmpty;
private int capacity;
BoxCar(BoxCarTarget<T, E> target, int ID, int cap) {
this.target = target;
boxID = ID;
isEmpty = true;
count = 0;
capacity = cap;
/*
* Here you can handle the payload.
* I think we can use reflection for
* extracting data.
*/
Map<T, E> payload = this.target.getPayload();
}
}
/**
* Class person
*/
class Person implements BoxCarTarget<String, String> {
private String government_ID, name;
private int age;
Person(String gov_ID, String Name, int Age) {
government_ID = gov_ID;
name = Name;
age = Age;
}
/**
* This method returns the data regarding to
* a specific BoxCar target.
*
* #return Map with specific data.
*/
#Override
public Map<String, String> getPayload() {
Map<String, String> payload = new HashMap<>();
payload.put("government_ID", government_ID);
payload.put("name", name);
payload.put("age", String.valueOf(age));
return payload;
}
}
/**
* Class Cargo
*/
class Cargo implements BoxCarTarget<String, String> {
private String cargo_ID;
private int height, weight;
Cargo(String c_id, int w, int h) {
cargo_ID = c_id;
height = h;
weight = w;
}
/**
* This method returns the data regarding to
* a specific BoxCar target.
*
* #return Map with specific data.
*/
#Override
public Map<String, String> getPayload() {
Map<String, String> payload = new HashMap<>();
payload.put("cargo_ID", String.valueOf(cargo_ID));
payload.put("height", String.valueOf(height));
payload.put("weight", String.valueOf(weight));
return payload;
}
}
Hope this helps!
I misunderstood your question previously. Here is what it should be:
public class BoxCarContents {
...
}
public class Person extends BoxCarContents {
...
}
public class Cargo extends BoxCarContents {
...
}
public class BoxCar<E extends BoxCarContents> {
E[] contents;
public BoxCar(int capacity) {
contents = new E[n];
}
...
}
//Alternative way
public class BoxCar {
BoxCarContents[] contents;
public BoxCar(BoxCarContents[] boxContents) {
contents = boxContents;
}
...
}
Basically the <E extends BoxCarContents> means E can be anything that extends BoxCarContents.
I have an java application where a object reference "Validate.Options" is passed as parameter to the function "ValidateResult(Validate.Options option)" and the function is called iterative. Within this function based on the certain condition the property "enableProcessing" of the passed object gets changed which does not get reset on the next iterate. How can I reset this property?
Below is the sample code.
public interface Validate
{
public List validate();
public class Options implements Serializable
{
public String name;
public boolean enableProcessing = true;
public Options(String name)
{
this.name = name;
}
}
}
public class Coder
{
public String name;
public int age;
public Coder(String name, int age)
{
this.name = name;
this.age = age;
}
public void ValidateResult(Validate.Options option)
{
if(option.name.equals(this.name) && option.enableProcessing)
{
option.enableProcessing = false;
//
//business logic and function call
//
}
}
public static void main(String[] args)
{
Validate.Options options = new Validate.Options("Test");
List<Coder> coders = new ArrayList<Coder>();
Coder coder = new Coder("Test", 28);
Coder coder1 = new Coder("XYZ", 18);
Coder coder2 = new Coder("Test", 16);
coders.add(coder);
coders.add(coder1);
coders.add(coder2);
for(Coder co : coders)
{
co.ValidateResult(options);
}
}
}
If I understood the question well - in your for loop, simply add a line of code to reset the value of your public Validate.Options.enableProcessing field
for(Coder co : coders)
{
//reset options object for the next iteration
options.enableProcessing = true;
co.ValidateResult(options);
}
Make options immutable if you do not want it to be changed:
public class Options implements Serializable
{
public final String name; // final prevents changes
public final boolean enableProcessing = true; // final prevents changes
public Options(String name)
{
this.name = name;
}
}
To locally work with enableProcessing copy its value to a local variable.
public void ValidateResult(Validate.Options option)
{
boolean enableProcessing = option.enableProcessing; // create local copy
if(option.name.equals(this.name) && enableProcessing) // use local copy
{
enableProcessing = false; // only change local copy
//
//business logic and function call
//
}
}
Alternatively create new, fresh Options for each loop:
public static void main(String[] args)
{
List<Coder> coders = Arrays. asList(
new Coder("Test", 28),
new Coder("XYZ", 18),
new Coder("Test", 16)
);
for(Coder co : coders)
{
Validate.Options options = new Validate.Options("Test"); // fresh options for each iteration
co.ValidateResult(options);
}
}
Suppose I am importing table entries, where a single entry can be stored in a class:
class Foo {
int i1;
int i2;
double d1;
}
After the import is complete, I will need to have access to the imported values themselves, as well as to their normalized versions. So far, I have implemented this functionality as follows:
class FooWithMaxTracking {
private int i1;
private static int i1_max=0;
public void setI1(int value){
this.i1 = value;
if (value > i1_max) { i1_max = value; }}
public int getI1(){
return i1;}
public double normI1(){
return i1/((double)i1_max);}
private int i2;
private static int i2_max=0;
public void setI2(int value){ <code identical to written above> }
public int getI2(){ ... }
public double normI2(){ ... }
// and another set of similar 2 variables & 3 functions for 'double d1'
}
In this implementation I strongly dislike the fact that I had to write the same code many times (only three in this example, but about ten times in the real project). Is there any way to make the code more DRY ("don't repeat yourself")?
If you do not mind a slight loss of performance, you can put all the maxima in a static Map, define a class that holds a getter, a setter, and a norm methods, and replace the individual variables with instances of that class:
private static Map<String,Object> max = new HashMap<String,Object>();
private static class IntMaxTrack {
private final String key;
private int value;
public IntMaxTrack(String k, int v) {
key = k;
value = v;
max.put(key, value);
}
public int get() { return value; }
public void set(int v) {
int m = ((Integer)max.get(key)).intValue();
value = v;
if (value > m) {
max.put(key, value);
}
}
public double norm() {
int m = ((Integer)max.get(key)).intValue();
return val / ((double)m);
}
}
Make a similar class for double, i.e. DblMaxTrack Now you can replace primitives with instances of these classes, and call their get, set, and norm from the corresponding methods of your class.
What about defining one class with the necessary code, like:
public class Bar {
private int i1;
private static int i1_max = 0;
public void setI1(int value) {
// ...
}
public int getI1() {
// ...
}
public double normI1() {
// ...
}
}
And using it sevearl times, like:
class FooWithMaxTracking {
one = new Bar();
two = new Bar();
three = new BarForDouble();
}
I use the enum to make a few constants:
enum ids {OPEN, CLOSE};
the OPEN value is zero, but I want it as 100. Is it possible?
Java enums are not like C or C++ enums, which are really just labels for integers.
Java enums are implemented more like classes - and they can even have multiple attributes.
public enum Ids {
OPEN(100), CLOSE(200);
private final int id;
Ids(int id) { this.id = id; }
public int getValue() { return id; }
}
The big difference is that they are type-safe which means you don't have to worry about assigning a COLOR enum to a SIZE variable.
See http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html for more.
Yes. You can pass the numerical values to the constructor for the enum, like so:
enum Ids {
OPEN(100),
CLOSE(200);
private int value;
private Ids(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
See the Sun Java Language Guide for more information.
whats about using this way:
public enum HL_COLORS{
YELLOW,
ORANGE;
public int getColorValue() {
switch (this) {
case YELLOW:
return 0xffffff00;
case ORANGE:
return 0xffffa500;
default://YELLOW
return 0xffffff00;
}
}
}
there is only one method ..
you can use static method and pass the Enum as parameter
like:
public enum HL_COLORS{
YELLOW,
ORANGE;
public static int getColorValue(HL_COLORS hl) {
switch (hl) {
case YELLOW:
return 0xffffff00;
case ORANGE:
return 0xffffa500;
default://YELLOW
return 0xffffff00;
}
}
Note that these two ways use less memory and more process units .. I don't say this is the best way but its just another approach.
If you use very big enum types then, following can be useful;
public enum deneme {
UPDATE, UPDATE_FAILED;
private static Map<Integer, deneme> ss = new TreeMap<Integer,deneme>();
private static final int START_VALUE = 100;
private int value;
static {
for(int i=0;i<values().length;i++)
{
values()[i].value = START_VALUE + i;
ss.put(values()[i].value, values()[i]);
}
}
public static deneme fromInt(int i) {
return ss.get(i);
}
public int value() {
return value;
}
}
If you want emulate enum of C/C++ (base num and nexts incrementals):
enum ids {
OPEN, CLOSE;
//
private static final int BASE_ORDINAL = 100;
public int getCode() {
return ordinal() + BASE_ORDINAL;
}
};
public class TestEnum {
public static void main (String... args){
for (ids i : new ids[] { ids.OPEN, ids.CLOSE }) {
System.out.println(i.toString() + " " +
i.ordinal() + " " +
i.getCode());
}
}
}
OPEN 0 100
CLOSE 1 101
The ordinal() function returns the relative position of the identifier in the enum. You can use this to obtain automatic indexing with an offset, as with a C-style enum.
Example:
public class TestEnum {
enum ids {
OPEN,
CLOSE,
OTHER;
public final int value = 100 + ordinal();
};
public static void main(String arg[]) {
System.out.println("OPEN: " + ids.OPEN.value);
System.out.println("CLOSE: " + ids.CLOSE.value);
System.out.println("OTHER: " + ids.OTHER.value);
}
};
Gives the output:
OPEN: 100
CLOSE: 101
OTHER: 102
Edit: just realized this is very similar to ggrandes' answer, but I will leave it here because it is very clean and about as close as you can get to a C style enum.
#scottf
An enum is like a Singleton. The JVM creates the instance.
If you would create it by yourself with classes it could be look like that
public static class MyEnum {
final public static MyEnum ONE;
final public static MyEnum TWO;
static {
ONE = new MyEnum("1");
TWO = new MyEnum("2");
}
final String enumValue;
private MyEnum(String value){
enumValue = value;
}
#Override
public String toString(){
return enumValue;
}
}
And could be used like that:
public class HelloWorld{
public static class MyEnum {
final public static MyEnum ONE;
final public static MyEnum TWO;
static {
ONE = new MyEnum("1");
TWO = new MyEnum("2");
}
final String enumValue;
private MyEnum(String value){
enumValue = value;
}
#Override
public String toString(){
return enumValue;
}
}
public static void main(String []args){
System.out.println(MyEnum.ONE);
System.out.println(MyEnum.TWO);
System.out.println(MyEnum.ONE == MyEnum.ONE);
System.out.println("Hello World");
}
}
public class MyClass {
public static void main(String args[]) {
Ids id1 = Ids.OPEN;
System.out.println(id1.getValue());
}
}
enum Ids {
OPEN(100), CLOSE(200);
private final int id;
Ids(int id) { this.id = id; }
public int getValue() { return id; }
}
#scottf, You probably confused because of the constructor defined in the ENUM.
Let me explain that.
When class loader loads enum class, then enum constructor also called. On what!! Yes, It's called on OPEN and close. With what values 100 for OPEN and 200 for close
Can I have different value?
Yes,
public class MyClass {
public static void main(String args[]) {
Ids id1 = Ids.OPEN;
id1.setValue(2);
System.out.println(id1.getValue());
}
}
enum Ids {
OPEN(100), CLOSE(200);
private int id;
Ids(int id) { this.id = id; }
public int getValue() { return id; }
public void setValue(int value) { id = value; }
}
But, It's bad practice. enum is used for representing constants like days of week, colors in rainbow i.e such small group of predefined constants.
I think you're confused from looking at C++ enumerators. Java enumerators are different.
This would be the code if you are used to C/C++ enums:
public class TestEnum {
enum ids {
OPEN,
CLOSE,
OTHER;
public final int value = 100 + ordinal();
};
public static void main(String arg[]) {
System.out.println("OPEN: " + ids.OPEN.value);
System.out.println("CLOSE: " + ids.CLOSE.value);
System.out.println("OTHER: " + ids.OTHER.value);
}
};