1

Im making a Coin class with a static arraylist that stores every instance of the class created, howevered I need to initiate that list with an initial instance, and I have not figured out how to do it without adding it twice (because of a redundant code), any suggestions?

public class Coin {
    private static ArrayList<String> coinNames = new ArrayList<>();
    private static ArrayList<String> coinAbbreviations = new ArrayList<>(Arrays.asList("CLP"));
    private static ArrayList<Coin> coins =
            new ArrayList<>(Arrays.asList(new Coin("Pesos chilenos", "CLP", 1f, "CLP")));
    private static HashMap<String,Float> exchangeRates;
    private String coinName;
    private String coinAbbreviation;
    private Float coinValue;
    private String unit;


    public Coin(String coinName, String coinAbbreviation, Float coinValue, String unit) {
        assert !coinAbbreviations.contains(coinAbbreviation) : "Coin abbreviation already used";
        assert coinAbbreviations.contains(unit) : "Coin unit non existent.";
        assert !coinNames.contains(coinName) : "Coin name already used.";
        this.coinName = coinName;
        this.coinAbbreviation = coinAbbreviation;
        this.coinValue = coinValue;
        this.unit = unit;

        coins.add(this);
    }
}
5
  • 1
    static arraylist that stores every instance not sure what are your trying to do Commented Sep 19, 2017 at 17:31
  • 2
    Please keep in mind that this pattern is inherently thread-unsafe (that is, you can basically never make thread-safe code with it), so it's a bad habit to get into. A better approach would be a private constructor, and a static factory method that calls that constructor and then adds the instance to coins. Commented Sep 19, 2017 at 17:31
  • Better would be to have a CoinFactory class which creates (and returns) Coin instances and adds them to itself. Your current solution is not thread-safe and that's just one drawback. Commented Sep 19, 2017 at 17:35
  • @DodgyCodeException could you explain please, i think that might be the solution Commented Sep 19, 2017 at 17:40
  • @NicolasQuiroz I've tried to explain; see my new answer below. Commented Sep 20, 2017 at 10:22

3 Answers 3

5

If you insist on having mutable static variables at all -- it's generally not a good idea to do things like this at all -- you could do

private static ArrayList<Coin> coins =
        new ArrayList<>();

static {
  new Coin("Pesos chilenos", "CLP", 1f, "CLP");
}

...which adds the element to the list immediately.

Sign up to request clarification or add additional context in comments.

4 Comments

what is a better idea then?
Have an actual class that stores all the coins you make. Don't make it tied to the constructor, list them all explicitly.
Hey I dont get the part when you said Don't make it tied to the constructor, list them all explicitly . By that you mean that whenever I instatiate it, the constructor won't automatically store it, but I have to do it manually?
Yes. Having your constructor automatically store things is dangerous and worrisome.
1

What stops you initialising your list in its declaration and then just adding each instance to the list in the constructor?

1 Comment

That's what the OP is doing, but what they want is for one Coin (the "Pesos chilenos") one to be "automatically" added, without the user of this class having to manually instantiate it.
0

You could alternatively design your application using some best-practice patterns. You want to keep a registry of all created coins. This is best kept outside of the Coin class itself. You could have a class that manages the creation of coins and keeps a list of those that it created. The Coin class itself can be an interface, if you like, as that way you ensure that it cannot be created other than by the CoinFactory.

public interface Coin {
    String name();
    String abbreviation();
    BigDecimal value();
    String unit();
}

And the Coin factory class:

public class CoinFactory {

    // Concrete coin is an internal implementation class whose details don't
    // need to be known outside of the CoinFactory class.
    // Users just see it as interface Coin.
    private static class ConcreteCoin implements Coin {
        private final String name;
        private final String abbreviation;
        private final BigDecimal value;
        private final String unit;

        ConcreteCoin(String name, String abbreviation, BigDecimal value, String unit) {
            this.abbreviation = abbreviation;
            this.name = name;
            this.value = value;
            this.unit = unit;
        }

        public String name() { return name; }
        public String abbreviation() { return abbreviation; }
        public BigDecimal value() { return value; }
        public String unit() { return unit; }
    }

    // Sets for enforcing uniqueness of names and abbreviations
    private Set<String> names = new HashSet<>();
    private Set<String> abbreviations = new HashSet<>();

    // All coins must have one of the following ISO currency codes as the 'unit' field.
    private final Set<String> allIsoCurrencyCodes =
            Set.of("CLP", "GBP", "EUR", "CAD", "USD", "XXX" /* , ... */);

    private List<Coin> allCoins = new ArrayList<>(
            List.of(createCoin("Pesos chilenos", "CLP", BigDecimal.ONE, "CLP")));

    private List<Coin> unmodifiableListOfAllCoins =
            Collections.unmodifiableList(allCoins);


    public Coin createCoin(String name, String abbreviation, BigDecimal value, String unit) {
        if (!names.add(name))
            throw new IllegalArgumentException("Name already exists: " + name);
        if (!abbreviations.add(abbreviation))
            throw new IllegalArgumentException("Abbreviation already exists: " + abbreviation);
        if (!allIsoCurrencyCodes.contains(unit))
            throw new IllegalArgumentException("Coin unit is not a recognised ISO currency code: " + unit);

        Coin coin = new ConcreteCoin(name, abbreviation, value, unit);
        allCoins.add(coin);
        return coin;
    }

    public Collection<Coin> allCoins() {
        return unmodifiableListOfAllCoins;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.