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);
}
}
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.
What stops you initialising your list in its declaration and then just adding each instance to the list in the constructor?
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;
}
}
Related
I am working in Java and I want to make a deep copy of a MoleculeDTO object. I tried to make a copy constructor too, but it is not working and it is refering to the initial object.
public class MoleculeDTO {
private int ID;
private String name;
private List<AtomDTO> atoms = new ArrayList<>();
private int nrAtoms =0;
public MoleculeDTO(String name, List<AtomDTO> atoms, int nrAtoms) {
this.name = name;
this.atoms = atoms;
this.nrAtoms = nrAtoms;
}
public MoleculeDTO(MoleculeDTO molecule) {
this(molecule.getName(), molecule.getAtoms(), molecule.getNrAtoms());
}
...getter, setter
}
Here is class AtomDTO.
public class AtomDTO{
private int ID;
private String name;
private String symbol;
private int nrOfBonds;
private List<BondDTO> bonds = new ArrayList<>();
private int type;
private AnchorNode anchorNode;
public AtomDTO(String name, String symbol, int nrOfBonds, List<BondDTO> bonds, int type) {
this.name = name;
this.nrOfBonds = nrOfBonds;
this.bonds = bonds;
this.type = type;
}
public AtomDTO(AtomDTO copyAtom) {
this(copyAtom.getName(),copyAtom.getSymbol(), copyAtom.getNrOfBonds(), copyAtom.getBonds(), copyAtom.getType());
}
...getter, setter
}
Here is class BondDTO.
public class BondDTO {
private int ID;
private int otherAtomID;
private int otherAtomType;
private int bondType;
public BondDTO(int otherAtomID, int otherAtomType, int bondType) {
this.otherAtomID = otherAtomID;
this.otherAtomType = otherAtomType;
this.bondType = bondType;
}
public BondDTO(BondDTO copyBond) {
this(copyBond.getOtherAtomID(), copyBond.otherAtomType, copyBond.bondType);
}
...getter, setter
}
Your copy constructors are just doing shallow copies of each field. That's fine for strings because they're immutable, and it's fine for ints because they're primitive (which means they lack identity and are immutable). In those cases, there is no important difference between shallow and deep copies. But it doesn't work in general for lists because lists can be mutable and so can their elements. So instead of just pointing at the same list, you need to make a new list and deep copy each element of the original list into the new one.
Use this helper method to make deep copies of any lists:
static <T> List<T> deepCopyList(List<T> list, UnaryOperator<T> deepCopyElement) {
return list.stream().map(deepCopyElement).collect(
Collectors.toCollection(ArrayList::new)
);
}
Like so:
public AtomDTO(AtomDTO that) {
this(that.getName(), that.getType(), deepCopyList(that.getBonds(), BondDTO::new));
}
I have an application where a user provides me with the name of a field, e.g name or costInCents, and I have to sort by that field. I have ways of guaranteeing that the field name will be correct. This application causes the complication that I simply cannot make my class Comparable and implement a specific compareTo(), since with a custom implementation of compareTo() I need to know which fields / methods to use at implementation time.
So to achieve this goal, I am trying to use reflection in order to match the field to its accessor. Here's a MWE of what I want to do.
Class Product is a simple POJO class whose instances I want to pairwise compare:
public class Product
{
final String name;
final Integer quantity;
final Long costInCents;
public Product(final String name, final Integer quantity, final Long costInCents)
{
this.name = name;
this.quantity = quantity;
this.costInCents = costInCents;
}
public String getName()
{
return name;
}
public Integer getQuantity()
{
return quantity;
}
public Long getCostInCents()
{
return costInCents;
}
}
And my Main class, which is currently incomplete:
public class Main {
public static void main(String[] args) {
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
// The following void methods are supposed to sort in-place with something like Arrays.sort() or Collections.sort(),
// but I am also open to solutions involving stuff like Stream::sorted() or similar ones, which return a sorted array.
sortByField(productArray, "costInCents");
sortByField(productArray, "name");
}
private void sortByField(final Product[] productArray, final String sorterFieldName)
{
final Field sorterField = getSorterField(sorterFieldName, LiteProduct.class); // Gets the Field somehow
final Method sorterAccessor = getSorterAccessor(sorterField, LiteProduct.class); // Given the Field, this is easy
Arrays.sort((Product p1, Product p2)->((Comparable<?>)sorterAccessor.invoke(p1)).compareTo(sorterAccessor.invoke(p2)) > 0); // Capture of ? instead of Object
}
}
Unfortunately, the Arrays.sort() line results in a compile-time error with message Capture of ? instead of Object. I have tried casting the second argument to Comparable<?>, Comparable<? super sorterField.getType(), etc, with no luck. Ideas?
Possibly the best way - with sorting strategies. No need for reflection, compatible with more complex sorting logic:
Map<String, Comparator<Product>> sortingStrategies = new HashMap<>(){
{
put("costInCents", Comparator.comparingLong(p->p.costInCents));
put("quantity", Comparator.comparingLong(p->p.quantity));
put("name", Comparator.comparing(p->p.name));
}
};
private void sortByField(final Product[] productArray, final String sorterFieldName)
{
Arrays.sort(productArray, sortingStrategies.get(sorterFieldName));
}
You could write a Comparator for each field and use it by name via a Map:
public class Product
{
private final static Map<String,Comparator<Product>> COMPARATORS;
static {
COMPARATORS = new HashMap<>();
COMPARATORS.put("name", new NameComparator());
COMPARATORS.put("costInCents", new CostInCentsComparator());
}
final String name;
final Integer quantity;
final Long costInCents;
public Product(final String name, final Integer quantity, final Long costInCents)
{
this.name = name;
this.quantity = quantity;
this.costInCents = costInCents;
}
public String getName()
{
return name;
}
public Integer getQuantity()
{
return quantity;
}
public Long getCostInCents()
{
return costInCents;
}
static class NameComparator implements Comparator<Product> {
#Override
public int compare(Product o1, Product o2) {
return o1.getName().compareTo(o2.getName());
}
}
static class CostInCentsComparator implements Comparator<Product> {
#Override
public int compare(Product o1, Product o2) {
return o1.getCostInCents().compareTo(o2.getCostInCents());
}
}
static Comparator<Product> getComparator(String name) {
return COMPARATORS.get(name);
}
}
and use that in the main class
public class Main {
public static void main(String[] args) {
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
// The following void methods are supposed to sort in-place with something like Arrays.sort() or Collections.sort(),
// but I am also open to solutions involving stuff like Stream::sorted() or similar ones, which return a sorted array.
sortByField(productArray, "costInCents");
sortByField(productArray, "name");
}
private static void sortByField(final Product[] productArray, final String sorterFieldName)
{
Arrays.sort(productArray, Product.getComparator(sorterFieldName));
}
}
You may have to do minor changes like makeing it null safe or something
you can try this:
public class Test{
public static void main(String arg[]){
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
Arrays.sort(productArray,(p1, p2) -> p1.getName().compareTo(p2.getName()));
for(Product p: productArray){
System.out.println(p.getName());
}
}
}
in this case Comparator is a functional interface so I used lambad expression. but you can do this too
So I am a student who just started with java and got this task.
''Make a class which represent an episode in a TVSeries. This should contain instance variables for episode, season, title and playtime. We would also make to constuctors to be able to create an episode, one with all the instance variables, and one without playtime (overloading).
Then make a class which represent a TVSeries. This should contain instance variables for title, description, release date and a list with episodes.
An episode shall be able to individually added via a methode addEpisodes(Episode theEpisode)''
So I have made the two classes (Episode with two constructors and TVSeries), but don't know what the addEpisodes(Episode theEpisode) methode shall contain. Would appreciate some help :)
public class TVSerie {
private String titel;
private String description;
private LocalDate releaseDate;
private ArrayList<Episode> listeWithEpisods;
public void addEpisode(Episode theEpisode) {
ArrayList<Episode> listeWithEpisods = new ArrayList<>();
listeWithEpisods.add(theEpisode);
System.out.println(listeWithEpisods);
}
public class Episode extends TVSerie {
private int episodeNumber;
private int sesongNumber;
private String titel;
private int playtime;
public Episode(int episodeNumber, int sesongNumber, String titel, int playtime) {
this.episodeNumber = episodeNumber;
this.sesongNumber = sesongNumber;
this.titel = titel;
this.playtime = spilletid;
}
public Episode(int episodeNummer, int sesongNummer, String tittel) {
this.episodeNumber = episodeNumber;
this.sesongNumber = sesongNumber;
this.titel = titel;
}
As the assignment suggest, TVSeries should have List and addEpisode needs to add it to your list.
public class TVSerie {
private String titel;
private String description;
private LocalDate releaseDate;
private List<Episode> listeWithEpisods;
public TVSerie(){
listeWithEpisods = new ArrayList<>();
}
public void addEpisode(Episode theEpisode) {
listeWithEpisods.add(theEpisode);
System.out.println(listeWithEpisods);
}
You need to initialize your list only once, inside the constructor.
In your implementation every time addEpisode is used you create new instance of your episode list and therefore deletes the former one.
In addition, Episode should not extends TVSerie, it is not a type of it. It is a type of it's own not related to TVSerie.
With this class:
public class MyClass implements Comparable<MyClass> {
private String status;
private String name;
private String firstName;
#Override
public int compareTo(MyClass o) {
return 0;
}
}
I'd like to sort a list of MyClass objects with this order:
Firstly, status = "open", then "working" then, "close"
Secondly, name = "toto", then "titi"
Finally, firstName = "tutu", "tata"
How can I do this with the Comparable interface ?
I would do this like so: first define a set of lists which define the order for each field:
private static List<String> statusOrder = Arrays.asList("open", "working", "close");
private static List<String> nameOrder = Arrays.asList("toto", "titi");
private static List<String> firstNameOrder = Arrays.asList("tutu", "tata");
Then use List.indexOf to get the position of the element in the list, and then simply subtract the results:
#Override
public int compareTo(MyClass o) {
final int statusComp = statusOrder.indexOf(status) - statusOrder.indexOf(o.status);
if (statusComp != 0) return statusComp;
final int nameComp = nameOrder.indexOf(name) - nameOrder.indexOf(o.name);
if (nameComp != 0) return nameComp;
return firstNameOrder.indexOf(firstName) - firstNameOrder.indexOf(o.firstName);
}
The issue with this approach is that indexOf will return -1 if the element is not in the list. You would need to define the behaviour in the case where MyClass contains non-standard values (perhaps it will never happen).
I have a Set<MultiAdminComponent> rootItems = new HashSet<>();HashSet.
In this I have all my Screen.
In my HashSet I am going to have all my rows. I want to sort the MultiAdminComponent based on rowId.
This is MultiAdminComponent
public class MultiAdminComponent {
private String componentName;
private String componentIdentification;
private String componentType;
private String componentState;
private String componentUrl;
private String componentId;
private String rowId;
private List<MultiAdminComponent> items;
private int componentStateId;
private int ctastatus;
private String actionId;
private String actionToPerform;
private int orderNumber;
private int ctarevision;
How can I sort based on RowId in MultiAdminComponent bean
Since you are on Java 8, you can leverage Stream API and Comparator.comparing() for this:
List<MultiAdminComponent> sortedList = rootItems.stream()
.sorted(Comparator.comparing(MultiAdminComponent::getRowId))
.collect(Collectors.toList()); // collect to whatever you want
Keep in mind that HashSet does not maintain order so you should keep the sorted result in some other data structure.
And remember that this is not going to sort your Set this is going to return a List of naturally sorted MultiAdminComponents and you need to capture the result of this operation.
Just to let you know, there are few more Sets.
HashSet is not ordered/sorted
LinkedHashSet sorted by the order that it's been inserted
TreeSet sorted in natural order
I know the question been answered, but truly I can't see a point of using a HashSet which is not ordered and then try to order it when you can just use a TreeSet?
Before Java 1.8 version, which can help you
public class Test {
public static void main(String[] args) {
MultiAdminComponent m1 = new MultiAdminComponent("1");
MultiAdminComponent m2 = new MultiAdminComponent("2");
MultiAdminComponent m3 = new MultiAdminComponent("3");
Set<MultiAdminComponent> set = new HashSet<MultiAdminComponent>();
set.add(m1);
set.add(m3);
set.add(m2);
List<MultiAdminComponent> list = new ArrayList<MultiAdminComponent>(set);
for (MultiAdminComponent m : list) {
System.out.println("before" + m.getRowId());
}
Collections.sort(list, new Comparator<MultiAdminComponent>() {
#Override
public int compare(MultiAdminComponent m1, MultiAdminComponent m2) {
return m1.getRowId().compareTo(m2.getRowId());
}
});
for (MultiAdminComponent m : list) {
System.out.println("after" + m.getRowId());
}
}
}
class MultiAdminComponent {
private String rowId;
public MultiAdminComponent(String rowId) {
super();
this.rowId = rowId;
}
public String getRowId() {
return rowId;
}
public void setRowId(String rowId) {
this.rowId = rowId;
}
}