Superclass resets already active objects - java

It's a little bit difficult but i'll try to explain my problem. I've created a program with a superclass (RichIndustrialist) two subclasses (PredecessorRichIndustrialist and another one I didn't add) and 4 subclasses to these subclasses (CrazyRichIndustrialist and another 3). Now, the program is too difficult to explain but the problem is actually simple. My constructor is in the superclass and every subclass use it to initilize. Every time I create a new subclass object like CrazyRichIndustrialist, it resets all the already existed subclasses (from any subclass) to the value of the new object. I don't know how to fix this. Thank you in advance...
RichIndustrialist:
package Mortal;
import java.util.Random;
public class RichIndustrialist implements Mortal {
private static String Name;
private static double holdings;
private static int Alive;
public RichIndustrialist(String Rich_Name, double Rich_holdings) {
this.Name = Rich_Name;
this.holdings = Rich_holdings;
this.Alive = 1;
}
public int isAlive() {
return (this.Alive);
}
public void setHoldings(double new_holdings) {
this.holdings = new_holdings;
}
public double getHoldings() {
return (this.holdings);
}
public String getName() {
return (this.Name);
}
public void die() {
this.Alive = 0;
}
public void getHeritage(double heritage) {
this.holdings = this.holdings + heritage;
}
}
PredecessorRichIndustrialist:
package Mortal;
import java.util.Arrays;
public class PredecessorRichIndustrialist extends RichIndustrialist {
private static String Name;
private static double holdings;
private RichIndustrialist[] successors = {};
private static int Alive;
public PredecessorRichIndustrialist(String Rich_Name, double Rich_holdings) {
super(Rich_Name,Rich_holdings);
}
public void die() {
super.die();
}
public void Inheritance(double holdings, RichIndustrialist[] successors) {
int i = 0;
while (i < successors.length) {
int Alive = successors[i].isAlive();
System.out.println(Alive);
if (Alive == 0) {
removeSuccessor(successors[i]);
i++;
} else {
i++;
}
}
}
public void addSuccessor(RichIndustrialist new_successor) {
RichIndustrialist[] new_successors = new RichIndustrialist[successors.length + 1];
if (successors.length == 0) {
new_successors[0] = new_successor;
successors = new_successors;
} else {
for (int i = 0; i < successors.length; i++) {
new_successors[i] = successors[i];
}
new_successors[new_successors.length - 1] = new_successor;
}
this.successors = new_successors;
}
public void removeSuccessor(RichIndustrialist removed_successor) {
RichIndustrialist[] new_successors = new RichIndustrialist[this.successors.length - 1];
int j = 0;
for (int i = 0; i < this.successors.length; i++) {
if (!this.successors[i].equals(removed_successor)) {
new_successors[j] = this.successors[i];
} else {
j--;
}
j++;
}
}
public RichIndustrialist[] getSuccessors() {
return successors;
}
}
CrazyRichIndustrialist:
package Mortal;
import java.util.Random;
public class CrazyRichIndustrialist extends PredecessorRichIndustrialist {
private RichIndustrialist[] successors = {};
private static String Name;
private static double holdings;
private static int Alive;
public CrazyRichIndustrialist(String Rich_Name, double Rich_holdings) {
super(Rich_Name,Rich_holdings);
}
public void die() {
super.die();
Inheritance(getHoldings(),getSuccessors());
}
public void addSuccessor(RichIndustrialist new_successor) {
super.addSuccessor(new_successor);
}
public void removeSuccessor(RichIndustrialist removed_successor) {
super.removeSuccessor(removed_successor);
}
public void Inheritance (double holdings , RichIndustrialist[] successors) {
super.Inheritance(holdings, successors);
for (int i=0; i<successors.length-1; i++)
{
double random = new Random().nextDouble();
double amount = this.holdings * random;
successors[i].getHeritage(amount);
holdings = this.holdings - amount;
}
successors[successors.length-1].getHeritage(this.holdings);
this.holdings = 0;
}
public String getName(){
return super.getName();
}
public double getHoldings(){
return super.getHoldings();
}
public RichIndustrialist[] getSuccessors(){
return super.getSuccessors();
}
public void setHoldings(double new_holdings){
super.setHoldings(new_holdings);
}
public int isAlive() {
return super.isAlive();
}
public void getHeritage(double heritage) {
super.getHeritage(heritage);
}
}

Most of your fields are static. What that means is that all the instances of your classes share the same value. When you call the constructor, the static fields are modified, which affects all the existing instances.
For example:
this.Name = Rich_Name;
should actually have been written:
RichIndustrialist.Name = Rich_Name;
You can read about the difference between instance and class (or static) members in this tutorial.

The following fields should be declared as non-static. When these fields are declared as static each RichIndustrialist instance will share these fields and their assigned values. Declaring them as non-static allows each RichIndustrialist instance to have its own copy of these fields, which is autonomous from the other instances of RichIndustrialist.
private String Name;
private double holdings;
private int Alive;
Here is a good description of static from the Java Tutorial
Sometimes, you want to have variables that are common to all objects.
This is accomplished with the static modifier. Fields that have the
static modifier in their declaration are called static fields or class
variables. They are associated with the class, rather than with any
object. Every instance of the class shares a class variable, which is
in one fixed location in memory. Any object can change the value of a
class variable, but class variables can also be manipulated without
creating an instance of the class.

Your properties/variables are static. and we know static variable are shared between all the objects.
That is the reason the last object will replace the existing value of your variables
Suggestion:
change your static modifier to instance modifier
From
private static String Name;
private static double holdings;
private static int Alive;
To
private String Name;
private double holdings;
private int Alive;
I am sure your problem will resolve.

You are declaring the Name member field in all of your classes, you should only declare it in the super-class and let the other sub-classes (re)use it.
Furthermore, you declared the field as static, all instances of your class will use the same field, which is probably not what you intended, so remove the static part.
Same goes for all of your other member fields.
Note: do not start the member fields with a capital: Name should be defined and used as name. Class names on the other hand should start with a capital! This is a generically accepted Java convention and keeps things more clear/separated.

Related

"actual and formal argument lists differ in length" error

I'm trying to create a class that will do everything that a different class can do, but it will use random integers in order to create the objects that would normally require user input. Here I have a Pokemon program where I have class where the user creates a Pokemon trainer by inputting their name, and the program will create an ArrayList where the trainer's Pokemon are stored. I have a subclass called ComputerTrainer where it should have the same functionality, but randomly generated Pokemon will be added to the trainer's list of Pokemon. I created a constructor that accesses the protected variables in the PokemonTrainer class, but I'm getting an error that says "reason: actual and formal argument lists differ in length". Why I am getting this error?
Here is the code for the PokemonTrainer class:
import java.util.ArrayList;
public class PokemonTrainer
{
// private constants
private static final int MAX_POKEMON = 2;
protected ArrayList<Pokemon> pokemonList;
protected String name;
protected int numOfPokemon;
// Write your PokemonTrainer class here
public PokemonTrainer(String name)
{
this.name = name;
pokemonList = new ArrayList<Pokemon>();
}
public boolean addPokemon(Pokemon p)
{
if(numOfPokemon < MAX_POKEMON)
{
pokemonList.add(p);
numOfPokemon++;
return true;
}
else
{
return false;
}
}
public boolean hasLost()
{
int numOfPokemonThatLost = 0;
for(Pokemon p : pokemonList)
{
if(p.hasFainted())
{
numOfPokemonThatLost++;
}
}
if(numOfPokemonThatLost == numOfPokemon)
{
return true;
}
else
{
return false;
}
}
public Pokemon getNextPokemon()
{
int nextPokemon = 0;
int numOfPokemonThatLost = 0;
for(Pokemon p : pokemonList)
{
while(p.hasFainted() && nextPokemon < numOfPokemon)
{
nextPokemon++;
numOfPokemonThatLost++;
if(nextPokemon < numOfPokemon)
{
p = pokemonList.get(nextPokemon);
}
}
}
if(numOfPokemonThatLost == numOfPokemon)
{
return null;
}
else
{
return pokemonList.get(nextPokemon);
}
}
public Pokemon getPokemon(int nPokemon)
{
return pokemonList.get(nPokemon);
}
public int getNumberOfPokemons()
{
return pokemonList.size();
}
public static int getMaxPokemon()
{
return MAX_POKEMON;
}
public String toString()
{
return name;
}
}
and here is the code for the ComputerTrainer subclass:
import java.util.ArrayList;
import java.util.Random;
public class ComputerTrainer extends PokemonTrainer
{
// private constants
// Possible pokemon names and move names to generate random Pokemon
private static final String[] POKEMON_NAMES = {"Pikachu", "Bulbasaur", "Charmander", "Squirtle"};
private static final String[] MOVE_NAMES = {"Tailwhip", "Bodyslam", "Splash", "Shock"};
private static final int MAX_DAMAGE = 25;
private static final int MAX_MOVES = 4;
private PokemonImages images = new PokemonImages();
// Write a Constructor that sets the name of the ComputerTrainer
// and adds 2 randomly generated Pokemon to itself
public ComputerTrainer(String name)
{
this.name = name;
pokemonList = new ArrayList<Pokemon>();
for(int i = 0; i < PokemonTrainer.getMaxPokemon(); i++)
{
Random num = new Random();
int randomNumber = num.nextInt(POKEMON_NAMES.length);
Pokemon p = new Pokemon (POKEMON_NAMES[randomNumber], images.getPokemonImage(POKEMON_NAMES[randomNumber]));
pokemonList.add(p);
numOfPokemon++;
}
}
/*
* Adds a randomly generated Pokemon to this ComputerTrainer's
* collection of Pokemon. A ComputerTrainer can only have 2
* Pokemon. This method returns true if there was room for the
* new Pokemon and it was successfully added, false otherwise.
*/
public boolean addRandomPokemon()
{
if(numOfPokemon < PokemonTrainer.getMaxPokemon())
{
Random num = new Random();
int randomNumber = num.nextInt(POKEMON_NAMES.length);
Pokemon p = new Pokemon (POKEMON_NAMES[randomNumber], images.getPokemonImage(POKEMON_NAMES[randomNumber]));
pokemonList.add(p);
numOfPokemon++;
return true;
}
else
{
return false;
}
}
// Returns a Move randomly chosen from the set of Moves
// that this trainer's current Pokemon knows.
// If all Pokemon have fainted, returns null.
public Move chooseRandomMove()
{
Pokemon currentBattlingPokemon = getNextPokemon();
// This method isn't finished yet
}
}
The program outputs the following error:
ComputerTrainer.java:20: error: constructor PokemonTrainer in class PokemonTrainer cannot be applied to given types;
{
^
required: String
found: no arguments
reason: actual and formal argument lists differ in length
The problem is that PokemonTrainer only has a constructor that has one String as parameter:
public class PokemonTrainer
{
public PokemonTrainer(String name) {
...
}
but you are not calling that constructor from ComputerTrainer:
public class ComputerTrainer extends PokemonTrainer
{
public ComputerTrainer(String name) {
this.name = name;
...
}
}
Java does not automatically call the constructor of the superclass that matches the actual constructor, it calls the default (parameter-less constructor) but the superclass does not have it.
Solution: add an explicit invokation of the correct constructor of the superclass:
public class ComputerTrainer extends PokemonTrainer
{
public ComputerTrainer(String name) {
super(name);
...
}
}
see Java Language Specification 8.8.7. Constructor Body for more details
Note: the error message is a bit confusing since there is like a hidden super() call as first statement in the ComputerTrainer constructor

Which overridden methods are invoked?

I am having hard time to understand the solution of the given question. I can't understand at each step which of the class' methods are invoked.
I tried to make a list for what are a,b,c declared types and actual types then try to chose overridden or overloaded methods but it is complex.
class Upper {
private int i;
private String name;
public Upper(int i) {
name = "Upper";
this.i = i;
}
public void set(Upper n) {
i = n.show();
}
public int show() {
return i;
}
}
class Middle extends Upper {
private int j;
private String name;
public Middle(int i) {
super(i + 1);
name = "Middle";
this.j = i;
}
public void set(Upper n) {
j = n.show();
}
public int show() {
return j;
}
}
class Lower extends Middle {
private int i;
private String name;
public Lower(int i) {
super(i + 1);
name = "Lower";
this.i = i;
}
public void set(Lower n) {
i = n.show();
}
public int show() {
return i;
}
}
class Tester {
public static void main(String[] args) {
Lower a = new Lower(1);
Middle b = a;
Upper c = new Middle(5);
a.set(c);
b.set(a);
c.set(b);
System.out.println(a.show());
System.out.println(b.show());
System.out.println(c.show());
}
}
What is printed as a result of System.out.println(a.show()); after the set commands? Answer is 1
What is printed as a result of System.out.println(b.show()); after the set commands? Answer is 1
What is printed as a result of System.out.println(c.show()); after the set commands? Answer is 1
I don't get why the answers of all these are 1. Also I can't tell which class' overridden or overloaded methods that "a.set(c); b.set(a); c.set(b);" uses. A detailed explanation would be really helpful.
a.set(c) uses the set-method from Middle, as that overrides the one from Upper and the (overloaded) set from Lower is not applicable because c is not an instance of Lower.
Therfore j is set to c.show() which returns c's attribute j, so it will be set to 5. Consequently the (Lower-)attribute i of a is never touched and remains at 1 when it is shown and printed.
Try to resolve the others yourself.

List add function does not operate properly?

public static void main(String[] args) {
// TODO Auto-generated method stub
List<item> l = new ArrayList<item>();
List<Integer> ll = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
l.add(new item(i,i));
ll.add(i);
}
System.out.println(l.get(4).getWeight());
System.out.println(ll.get(4));
}
public class item {
private static int value;
private static int weight;
public item(int val, int w) {
setValue(val);
setWeight(w);
}
public static int getValue() {
return value;
}
public static void setValue(int value) {
item.value = value;
}
public static int getWeight() {
return weight;
}
public static void setWeight(int weight) {
item.weight = weight;
}
}
This is my code, and then item is class take two paratemers. But when I add the item into list, the elelments in list have same value(in this case it is 9). For Integer, there is no problem. I think I miss some critical parts of java feature.
Any help appreciated, thank you in advance.
All of your methods and members of item are static. That is, they belong to the item class, rather than a specific instance of that class. The static members are shared among every instance of the class, and so every new item you create is using the same set of data. You will want to make them not be static.
Check out the following official tutorials for more info, they are concise and well-written and will help you:
Non-static, member variables: Declaring Member Variables
Non-static, methods: Defining Methods
static class members: Understanding Class Members
Once you have done this, as Takendarkk astutely points out in a comment, be sure to use this.value = ... instead of item.value = ... (no longer valid) or value = ... (uses local scope value instead of member).

DRY maxima tracking

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

Named Parameter idiom in Java

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.

Categories

Resources