Grouping list by variables and counting sums of object variables - java

I must group elements from given list using stream. I want to put them into map (do groupping by variable
'vat' <key=vat, value=list>), then count sum of every objects variable in each key.
I am being stuck in summing stream. I did groupping stream but now, after few hours of coding i still dont know what to do.
Code of function:
public static List<Product> calculatingTaxes(List<Product> products){
Map<Double, List<Product>> productTaxesMap = new HashMap<>();
productTaxesMap = products.stream()
.collect(Collectors.groupingBy(Product::getVat));
System.out.println(productTaxesMap);
return null;
}
sout function is to see what the function is doing, current output
{1.0=[Product{netPrice=100.0, vat=1.0, vatAmount=0.0, grossPrice=100.0},
Product{netPrice=100.0, vat=1.0, vatAmount=0.0, grossPrice=100.0}], 1.23=
[Product{netPrice=100.0, vat=1.23, vatAmount=23.0, grossPrice=123.0},
Product{netPrice=100.0, vat=1.23, vatAmount=23.0, grossPrice=123.0},
Product{netPrice=100.0, vat=1.23, vatAmount=23.0, grossPrice=123.0}], 1.08=
[Product{netPrice=100.0, vat=1.08, vatAmount=8.0, grossPrice=108.0},
Product{netPrice=100.0, vat=1.08, vatAmount=8.0, grossPrice=108.0}]}
code of Product class:
public class Product {
private double netPrice;
private double vat;
private double vatAmount;
private double grossPrice;
public Product(double netPrice, double vat) {
this.netPrice = netPrice;
this.vat = vat;
this.grossPrice = netPrice * vat;
this.vatAmount = grossPrice - netPrice;
}
public double getNetPrice() {
return netPrice;
}
public double getVatAmount() {
return vatAmount;
}
public double getGrossPrice() {
return grossPrice;
}
public double getVat() {
return vat;
}
#Override
public String toString() {
return "Product{" +
"netPrice=" + netPrice +
", vat=" + vat +
", vatAmount=" + vatAmount +
", grossPrice=" + grossPrice +
'}';
}
I want the upper function, to return sum of netPrice, grossPrice and vat amount to every vat key(0-8-23%).
I tried collecting and summing elements using Collectors.grouppingBy(). by filtering etc, but none of them worked.

Assuming your input is:
List<Product> products = Arrays.asList(
new Product(100.0, 1.0),
new Product(100.0, 1.0),
new Product(100.0, 1.23),
new Product(100.0, 1.23),
new Product(100.0, 1.23),
new Product(100.0, 1.08),
new Product(100.0, 1.08)
);
You can do:
Map<Double, Product> vatToReducedProduct = products.stream()
.collect(Collectors.toMap(Product::getVat,
Function.identity(),
(p1, p2) -> new Product(p1.getNetPrice() + p2.getNetPrice(), p1.getVat())));
Output:
{
1.0=Product{netPrice=200.0, vat=1.0, vatAmount=0.0, grossPrice=200.0},
1.23=Product{netPrice=300.0, vat=1.23, vatAmount=69.0, grossPrice=369.0},
1.08=Product{netPrice=200.0, vat=1.08, vatAmount=16.0, grossPrice=216.0}
}

Related

Performing multiple reduction operations using Streams

I'm attempting to Stream a list of Objects to aggregate the int min and int max based on the grouping of several Field attributes.
public class OccupancyEntry {
private final int entryID;
private final String attribute1;
private final String attribute2;
private final String attribute3;
private final int min;
private final int max;
public OccupancyEntry(int entryID, String attribute1, String attribute2, String attribute3, int min, int max) {
this.entryID = entryID;
this.attribute1 = attribute1;
this.attribute2 = attribute2;
this.attribute3 = attribute3;
this.min = min;
this.max = max;
}
}
I'd like to map the above Objects to a a list of the following:
public class OccupancyAggregated {
private final LocalDate date;
private final String attribute1;
private final String attribute2;
private final String attribute3;
private final int min;
private final int max;
public OccupancyAggregated(LocalDate date, String attribute1, String attribute2, String attribute3, int min, int max) {
this.date = date;
this.attribute1 = attribute1;
this.attribute2 = attribute2;
this.attribute3 = attribute3;
this.min = min; //these are summed values
this.max = max; //these are summed values
}
}
My attempt so far. Through the help of this answer I've been able to group the entries by a set of fields, but using this method I can no longer get the mapping and reducing functions to work.
OccupancyEntry entry1 = new OccupancyEntry(1, "1", "2", "3", 1, 10);
OccupancyEntry entry2 = new OccupancyEntry(1, "1", "2", "3", 1, 10);
OccupancyEntry entry3 = new OccupancyEntry(1, "A", "B", "C", 1, 10);
ArrayList<OccupancyEntry> occupancyEntries = new ArrayList<>();
occupancyEntries.add(entry1);
occupancyEntries.add(entry2);
occupancyEntries.add(entry3);
LocalDate date = LocalDate.now();
ArrayList<OccupancyAggregated> aggregated = new ArrayList<>();
Map<List<String>, List<OccupancyEntry>> collect = occupancyEntries.stream()
.collect(groupingBy(x -> Arrays.asList(x.getAttribute1(), x.getAttribute2(), x.getAttribute3())));
The sought after output. Where the min and max fields are reduced from from the entirety of the grouped OccupancyEntry list.
ArrayList<OccupancyAggregated> aggregated = new ArrayList<>();
My previous attempts have consisted out of creating multiple streams which reduce either the min field or the max field based on String concatenated attribute fields.
final Map<String, Integer> minOccupancy = occupancyEntries.stream()
.collect((groupingBy(OccupancyEntry::getGroupedAttributes,
mapping(OccupancyEntry::getMin,
reducing(0, Integer::sum)))));
final Map<String, Integer> maxOccupancy = occupancyEntries.stream()
.collect((groupingBy(OccupancyEntry::getGroupedAttributes,
mapping(OccupancyEntry::getMax,
reducing(0, Integer::sum)))));
Afterwards I'd for loop through one of the maps and then start creating a new list with OccupancyAggregated objects and look up the values in both maps to construct it. This seemed much too convoluted.
I've also been trying to perform the reduce operation in one pass using this answer but I'm not sure how to get it to map to the new Class type properly.
occupancyEntries.stream()
.reduce((x, y) -> new OccupancyAggregated(
date,
x.getAttribute1(),
x.getAttribute2(),
x.getAttribute3(),
x.getMin() + y.getMin(),
x.getMax() + y.getMax()
))
.orElse(new OccupancyAggregated(date, "no data", "no data", "no data", 0, 0));
This is a very common request that's messy to solve with streams, because there's no concept of an "empty" or "identity" instance of the aggregate. I prefer the semi-imperative approach using a loop and Map.merge():
Map<List<String>, OccupancyAggregated> grouped = new HashMap<>();
for (OccupancyEntry e : occupancyEntries) {
grouped.merge(Arrays.asList(e.attribute1, e.attribute2, e.attribute3),
OccupancyAggregated.from(e, date),
OccupancyAggregated::merge);
}
List<OccupancyAggregated> aggregated = new ArrayList<>(grouped.values());
Where the merge() method looks like this:
public OccupancyAggregated merge(OccupancyAggregated o) {
return new OccupancyAggregated(
date, attribute1, attribute2, attribute3, min + o.min, max + o.max);
}
Alternatively, if you can make the aggregate mutable, you can update min/max in place:
OccupancyAggregated agg = grouped.computeIfAbsent(
Arrays.asList(e.attribute1, e.attribute2, e.attribute3),
attributes -> OccupancyAggregated.from(attributes, date));
agg.add(e.min, e.max);
I left out some of the new method implementations for the sake of brevity. Let me know if they need more elaboration.
You could do this:
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class AggregateToGetMinMax {
public static void main(String[] args) {
List<OccupancyEntry> list = setup();
List<OccupancyAggregated> result = aggregate(list, LocalDate.now());
System.out.println("\nresult: " + result);
}
public static List<OccupancyEntry> setup() {
OccupancyEntry[] entries = {
new OccupancyEntry(1, "1", "2", "3", 1, 10),
new OccupancyEntry(1, "1", "2", "3", 1, 10),
new OccupancyEntry(1, "A", "B", "C", 1, 10)
};
return List.of(entries);
}
public static List<OccupancyAggregated> aggregate(List<OccupancyEntry> occupancyEntries, LocalDate date) {
class MinMax {
int max = 0;
int min = 0;
public MinMax() {
}
public MinMax(OccupancyEntry oe) {
this.max = oe.max;
this.min = oe.min;
}
public MinMax add(MinMax mm) {
this.max += mm.max;
this.min += mm.min;
return this;
}
public String toString() {
return "min: " + min + "; max: " + max;
}
}
Map<String, List<OccupancyEntry>> groupedEntries = occupancyEntries.stream()
.collect(Collectors.groupingBy(OccupancyEntry::getGroupedAttributes));
System.out.println("grouped entries: ");
groupedEntries.entrySet().stream()
.forEach(entry -> System.out.println(entry));
List<OccupancyAggregated> result = groupedEntries.values().stream()
.map(list -> {
MinMax mm = list.stream()
.map(MinMax::new)
.reduce(
new MinMax(),
(MinMax acc, MinMax item) -> acc.add(item));
// It's okay to get(0) because all entries with have values with at least one item
// in the list.
OccupancyAggregated aggregated = new OccupancyAggregated(date, list.get(0), mm.min, mm.max);
return List.of(aggregated);
})
.collect(Collectors.toList()).stream()
.flatMap(List::stream)
.collect(Collectors.toList());
return result;
}
public static class OccupancyEntry {
private final int entryID;
private final String attribute1, attribute2, attribute3;
public final int min, max;
public OccupancyEntry(int entryID, String attribute1, String attribute2, String attribute3, int min, int max) {
this.entryID = entryID;
this.attribute1 = attribute1;
this.attribute2 = attribute2;
this.attribute3 = attribute3;
this.min = min;
this.max = max;
}
public String getGroupedAttributes() {
return List.of(attribute1, attribute2, attribute3).stream()
.collect(Collectors.joining("|"));
}
#Override
public String toString() {
return "OccupancyEntry [" + entryID + ", " + attribute1 + ", " + attribute2
+ ", " + attribute3 + ", " + min + ", " + max + "]";
}
}
public static class OccupancyAggregated {
final LocalDate date;
String attribute1, attribute2, attribute3;
private int min, max;
public OccupancyAggregated(LocalDate date, OccupancyEntry oe, int min, int max) {
this.date = date;
this.attribute1 = oe.attribute1;
this.attribute2 = oe.attribute2;
this.attribute3 = oe.attribute3;
this.min = min; // these are summed values
this.max = max; // these are summed values
}
#Override
public String toString() {
return "OccupancyAggregated: ( " +
attribute1 + ", " +
attribute2 + ", " +
attribute3 + ", " +
min + ", " +
max +
" )";
}
}
}
Note that I have separated the grouping and reducing so that one can more clearly focus on the reducing part of the work. Otherwise, building the entire operation straight through might become a bit tedious to mentally parse the important operation.
Output:
grouped entries:
A|B|C=[OccupancyEntry [1, A, B, C, 1, 10]]
1|2|3=[OccupancyEntry [1, 1, 2, 3, 1, 10], OccupancyEntry [1, 1, 2, 3, 1, 10]]
result: [OccupancyAggregated: ( A, B, C, 1, 10 ), OccupancyAggregated: ( 1, 2, 3, 2, 20 )]
The more succinct version of accumulate() looks like this:
public static List<OccupancyAggregated> aggregate(List<OccupancyEntry> occupancyEntries, LocalDate date) {
class MinMax {
int max = 0;
int min = 0;
public MinMax() {
}
public MinMax(OccupancyEntry oe) {
this.max = oe.max;
this.min = oe.min;
}
public MinMax add(MinMax mm) {
this.max += mm.max;
this.min += mm.min;
return this;
}
public String toString() {
return "min: " + min + "; max: " + max;
}
}
List<OccupancyAggregated> result = occupancyEntries.stream()
.collect(Collectors.groupingBy(OccupancyEntry::getGroupedAttributes))
.values().stream()
.map(list -> {
MinMax mm = list.stream()
.map(MinMax::new)
.reduce(
new MinMax(),
(MinMax acc, MinMax item) -> acc.add(item));
// It's okay to get(0) because all entries with have values with at least one item
// in the list.
OccupancyAggregated aggregated = new OccupancyAggregated(date, list.get(0), mm.min, mm.max);
return List.of(aggregated);
})
.collect(Collectors.toList()).stream()
.flatMap(List::stream)
.collect(Collectors.toList());
return result;
}

How to aggregate multiple fields using Collectors in Java

I have a custom Object Itemized which has two fields amount and tax. I have an array of Itemized objects and I am looking to sum the two fields in the same stream. Below is how I am calculating the sum of both the fields.
double totalAmount = Arrays.stream(getCharges()).map(Itemized::getAmount).reduce(0.0, Double::sum));
double totalTax = Arrays.stream(getCharges()).map(Itemized::getTax).reduce(0.0, Double::sum));
Is there any way I don't have to parse the stream two times and can sum the two fields in one go ? I am not looking to sum totalTax and totalAmount but want their sum separately. I was looking at Collectors but was not able to find any example which would allow aggregating of multiple fields in one go.
use a for loop ?
double taxSum = 0;
double amountSum = 0;
for (Itemized itemized : getCharges()) {
taxSum += itemized.getTax();
amountSum += itemized.getAmount();
}
You can try to use the teeing Collector, like so:
Arrays.stream(getCharges()) // Get the charges as a stream
.collect(Collectors // collect
.teeing( // both of the following:
Collectors.summingDouble(Itemized::getAmount), // first, the amounts
Collectors.summingDouble(Itemized::getTax), // second, the sums
Map::entry // and combine them as an Entry
)
);
This should give you a Map.Entry<Double, Double> with the sum of amounts as the key and the sum of tax as the value, which you can extract.
Edit:
Tested and compiled it - it works. Here we go:
ItemizedTest.java
public class ItemizedTest
{
static Itemized[] getCharges()
{
// sums should be first param = 30.6, second param = 75
return new Itemized[] { new Itemized(10, 20), new Itemized(10.4,22), new Itemized(10.2, 33) };
}
public static void main(String[] args)
{
Map.Entry<Double, Double> sums = Arrays.stream(getCharges())
.collect(Collectors
.teeing(
Collectors.summingDouble(Itemized::getAmount),
Collectors.summingDouble(Itemized::getTax),
Map::entry
)
);
System.out.println("sum of amounts: "+sums.getKey());
System.out.println("sum of tax: "+sums.getValue());
}
}
Itemized.java
public final class Itemized
{
final double amount;
final double tax;
public double getAmount()
{
return amount;
}
public double getTax()
{
return tax;
}
public Itemized(double amount, double tax)
{
super();
this.amount = amount;
this.tax = tax;
}
}
Output:
sum of amounts: 30.6
sum of tax: 75.0
P.S.: teeing Collector is only available in Java 12+.
Instead of summing by field, you define a custom object to hold both field's sum values:
ItemizedValues {
private double amount;
private double tax;
public static final ItemizedValues EMPTY = new ItemizedValues(0, 0);
// Constructor - getter - setter
public static ItemizedValues of(Itemized item) {
return new ItemizedValues(amount, tax);
}
public static ItemizedValues sum(ItemizedValues a, ItemizedValues b) {
// Sum the fields respectively
// It's your choice to reuse the existing instances, modify the values or create a brand new one
}
}
Arrays.stream(getCharges())
.map(ItemizedValues::of)
.reduce(ItemizedValues.EMPTY, ItemizedValues::sum);
With a data structure that can allow one to accumulate both sums, you can reduce the stream to a single object.
This is using double[] to hold totalAmount at index 0 and totalTax at index 1 (other options include SimpleEntry, Pair):
double[] res = Arrays.stream(getCharges())
.map(ch -> new double[] { ch.getAmount(), ch.getTax() })
.reduce(new double[] { 0, 0 },
(a1, a2) -> new double[] { a1[0] + a2[0], a1[1] + a2[1] });
double totalAmount = res[0],
totalTax = res[1];
You can do it by using Entry but still you will end up in creating lot of objects, the best solution i would suggest is for loop answered by NimChimpsky
Entry<Double, Double> entry = Arrays.stream(new Itemized[] {i1,i2})
.map(it->new AbstractMap.SimpleEntry<>(it.getAmount(), it.getTax()))
.reduce(new AbstractMap.SimpleEntry<>(0.0,0.0),
(a,b)->new AbstractMap.SimpleEntry<>(a.getKey()+b.getKey(),a.getValue()+b.getValue()));
System.out.println("Amount : "+entry.getKey());
System.out.println("Tax : "+entry.getValue());
In your specific case, it's could be done by using your Itemized class as value holder.
Itemized result = Arrays.stream(getCharges())
.reduce(new Itemized(), (acc, item) -> {
acc.setAmount(acc.getAmount() + item.getAmount());
acc.setTax(acc.getTax() + item.getTax());
return acc;
});
double totalAmount = result.getAmount();
double totalTax = result.getTax();

How to save the results of a called method of all the objects in an array?

I am creating a program that handles a car dealership. The user has the opportunity to add a car in the store by creating a random 3 digit number.
Now the question is how I can search/delete cars depending on the 3 digit code?
I'm thinking that I need every code that the cars have to save it on an array so I can search and delete afterwards.
I have created a class and certain methods on it, I have also created 5 objects and I'm trying to see if it works on these 5.
Here is the method of the random number:
I use the metritis variable because I can't achieve to place correctly the values on the array so I have to give parameter of 1,2,3,4,5 so I can place them correctly to the array.
package antiprosopeia;
import java.util.Random;
public class Antiprosopeia {
private String company,colour;
private int model,horsePower,speed,price,specialCode,metritis;
private int[] codes = new int[]{0,0,0,0,0};
public Antiprosopeia(String company, String colour, int model, int horsePower, int speed, int price) {
this.company = company;
this.colour = colour;
this.model = model;
this.horsePower = horsePower;
this.speed = speed;
this.price = price;
}
public Antiprosopeia() {
company = ""; colour = ""; model = 0; horsePower = 0; speed = 0; price = 0;
}
public void setRandomNumber(int metritis) {
Random rand = new Random();
int randNum2 = rand.nextInt(900) + 100;
specialCode = randNum2;
codes[metritis] = specialCode;
}
public void printarray() {
for(int i=0; i<codes.length; i++) {
System.out.println(" " + codes[i]);}
}
public void Info() {
System.out.println("Company : " + company + "\nColour : " + colour + "\nModel : " + model + "\nHorse Power : " + horsePower +
"\nSpeed : " + speed + "\nPrice : " + price );
}
public static void main(String[] args) {
Antiprosopeia car1 = new Antiprosopeia("Toyota","red",333,100,2223,8000);
car1.setRandomNumber(0);
Antiprosopeia car2 = new Antiprosopeia("Mercedes","yellow",233,100,2990,9000);
car2.setRandomNumber(1);
Antiprosopeia car3 = new Antiprosopeia("Volkswagen","green",153,100,2780,6000);
car3.setRandomNumber(2);
Antiprosopeia car4 = new Antiprosopeia("Mitsubisi","white",678,140,2600,7000);
car4.setRandomNumber(3);
Antiprosopeia car5 = new Antiprosopeia("Porsche","black",390,1000,2000,30000);
car5.setRandomNumber(4);
}
}
[EDIT] Now when i call the printarray() method it seems that at my array only one value is hold and all the others are zer0s as i defined the array at start of my program
If I were doing this, I would use a HashMap. This way you know that you have a unique 3 digit number, and if you wanted to, you could also store more data. You could do something like:
HashMap<Integer, Car> cars = new HashMap<Integer, Car>();
This example would allow you to add a car object to the map. You don't have to that, but it's an option. If you didn't want to do that, you could do:
HashMap<Integer, String> cars = new HashMap<Integer, String>();
and then do:
cars.put(123, "Description of car");
Using a HashMap would give you more options when storing the data. This would also prevent you from creating an array with 1000 elements, all of which are 0 until you have a value for them. You could easily print out all your numbers by doing:
for(int number : cars.entrySet()){
System.out.println("My car number: " + number);
}
Searching for keys would extremely easy, as you could do:
String description = cars.getKey(123);
If description was null, you would know that there is no key for it.
Your issue is that each Antiprosopeia object has its own codes array. They are not shared.
If you really want each object to have a Random ID, then assign that within the constructor.
public class Antiprosopeia {
private String company,colour;
private int model,horsePower,speed,price,specialCode,metritis;
private int randID;
public Antiprosopeia(String company, String colour, int model, int horsePower, int speed, int price){
this.company = company;
this.colour = colour;
this.model = model;
this.horsePower = horsePower;
this.speed = speed;
this.price = price;
this.randID = new Random().nextInt(900) + 100;
}
public Antiprosopeia(){
this("", "", 0, 0, 0, 0);
}
public int getID() { return this.randID; }
#Override
public String toString() {
return String.format(
"Company : %s\n" +
"Colour : %s\n" +
"Model : %s\n" +
"Horse Power : %d\n" +
"Speed : %d\n" +
"Price : %d\n",
company, colour, model, horsePower, speed, price
);
}
If you want to print all those objects,
public static void main(String[] args) {
List<Antiprosopeia> cars = new ArrayList<Antiprosopeia>();
cars.add(new Antiprosopeia("Toyota","red",333,100,2223,8000));
cars.add(new Antiprosopeia("Mercedes","yellow",233,100,2990,9000));
for (int i = 0; i < cars.size(); i++) {
Antiprosopeia c = cars.get(i);
System.out.println(c.getID());
System.out.println(c);
}
}

Count values from Java Object?

I have this Java object which is used to store item:
public class PaymentDetailsItem
{
private String name;
private String amount;
private int quantity;
private String currencyID;
public PaymentDetailsItem(String name, String amount, int quantity, String currencyID){
this.name = name;
this.amount = amount;
this.quantity = quantity;
this.currencyID = currencyID;
}
............
}
I use a List to store several Objects. How can I sum up the total amount from every object store into the List?
You could make use of Java 8 Stream API and implement something like this:
public static void main(String[] args) {
PaymentDetailsItem payment = new PaymentDetailsItem("test", "100.00", 10, "1");
PaymentDetailsItem payment2 = new PaymentDetailsItem("test number 2", "250.00", 10, "2");
List<PaymentDetailsItem> payments = new ArrayList<>();
payments.add(payment);
payments.add(payment2);
List<String> amounts = payments.stream().map(PaymentDetailsItem::getAmount).collect(Collectors.toList());
System.out.println("Here we have the extracted List of amounts: " + amounts);
String totalAmount = amounts.stream()
.reduce((amount1, amount2) -> String.valueOf(Float.valueOf(amount1) + Float.valueOf(amount2))).get();
System.out.println("Total amount obtained by using .reduce() upon the List of amounts: " + totalAmount);
System.out.println("Or you can do everything at once: " + payments.stream().map(PaymentDetailsItem::getAmount)
.reduce((amount1, amount2) -> String.valueOf(Float.valueOf(amount1) + Float.valueOf(amount2))).get());
}
Remember to implement the getter for the amount attribute.

Converting the same String value into an Object

I have an object share:
Share tea = new Share("TEA", "Common", 0, 100);
ArrayList<Share> shares = new ArrayList<Share>();
shares.add(tea);
What I'd like to do is, reading parameters from the keybord, convert directly the "tea" string into a share tea object :
Trade trade = new Trade( tea, Boolean.parseBoolean(buyOrSell), Integer.parseInt(quantity), Double.parseDouble(tradePrice));
What should I put instead of tea because my constructor is waiting a Share and not a String. The user is entering a string and I don't need ton create a new instance, I have to use the Share object "tea" that already exists.
The Share.java class :
public class Share {
private String shareSymbol = "";
private String type = "Common";
private double lastDividend = 0;
private double fixedDividend = 0;
private int parValue = 0;
// Calucul values
public String getShareSymbol() {
return shareSymbol;
}
public String getType() {
return type;
}
public double getLastDividend() {
return lastDividend;
}
public double getFixedDividend() {
return fixedDividend;
}
public int getParValue() {
return parValue;
}
// Constructor without Fixed Dividend
public Share(String shareSymbol, String type, int lastDividend, int parValue) {
this.shareSymbol = shareSymbol;
this.type = type;
this.lastDividend = lastDividend;
this.parValue = parValue;
}
// Constructor with Fixed Dividend
public Share(String shareSymbol, String type, int lastDividend,
int fixedDividend, int parValue) {
this(shareSymbol, type, lastDividend, parValue);
this.fixedDividend = fixedDividend / 100.0;
}
public String toString(){
String result="";
result += shareSymbol + " "+type + " " + lastDividend + " " + fixedDividend + " " + parValue + "\n";
return result;
}
}
The Trade.java class :
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
// The class trade allows the stock, the quantity and the price to be intialised
public class Trade {
Share share;
private int quantity;
double price;
private double dividendYield;
private double pERatio;
private boolean buyOrSell;
private Date tradeDate;
public Trade(Share share, boolean buyOrSell, int quantity, double price) {
this.share = share;
this.buyOrSell = buyOrSell;
this.quantity = quantity;
this.price = price;
tradeDate = Calendar.getInstance().getTime();
}
public String toString() {
String result = "";
result += "stock symbol : " + share.getShareSymbol() + " \n";
result += "Buy or Sell : " + buyOrSell + " \n";
result += "quantity :" + quantity + " \n";
result += "price : " + price + " \n";
result += "Dividend Yield : " + dividendYield + " \n";
result += "P/E Ratio : " + pERatio + " \n";
result += "tradeDate : " + tradeDate + " \n\n";
return result;
}
public Share getShare() {
return share;
}
public int getQuantity() {
return quantity;
}
public double getPrice() {
return price;
}
public double getDividendYield() {
return dividendYield;
}
public double getpERatio() {
return pERatio;
}
public Date getTradeDate() {
return tradeDate;
}
public double calcDividendYield() {
if ("Common".equalsIgnoreCase(share.getType())) {
dividendYield = share.getLastDividend() / price;
} else if ("Preferred".equalsIgnoreCase(share.getType())) {
dividendYield = share.getFixedDividend() * share.getParValue()
/ price;
}
return dividendYield;
}
public double calcPERatio() {
if (dividendYield > 0)
pERatio = price / dividendYield;
return pERatio;
}
}
Your constructor is waiting a share. So give it:
/* Read parameters from keyboard, stock in s1, s2, i1 and i2 variables */
Trade trade = new Trade( new Share(s1,s2,i1,i2), Boolean.parseBoolean(buyOrSell), Integer.parseInt(quantity), Double.parseDouble(tradePrice));
Otherwise you can implement a method (in Share class) that do it for you
public static Share stringToShare(String s1, String s2, int t1, int t2){
return new Share(s1, s2, t1, t2);
}
And then:
Trade trade = new Trade( Share.stringToShare(...), Integer.parseInt(quantity), Double.parseDouble(tradePrice));
EDIT: better use real variable names that means something, not s1, s2, etc.
I've got around of this, by creating a new constructor :
Trade trade = new Trade(shares, stockSymbol, Boolean.parseBoolean(buyOrSell),
Integer.parseInt(quantity), Double.parseDouble(tradePrice));
This is then the new constructor :
public Trade(ArrayList<Share> shares, String stockSymbol,
boolean buyOrSell, int quantity, double price) {
Iterator<Share> iter = shares.iterator();
int index = -1;
while (iter.hasNext()) {
Share share = iter.next();
index++;
if (stockSymbol.equalsIgnoreCase((share.getShareSymbol()))) {
this.share = shares.get(index);
this.buyOrSell = buyOrSell;
this.quantity = quantity;
this.price = price;
tradeDate = Calendar.getInstance().getTime();
break;
}
}
}
It's a bit complacated, because I had also to create a new method to get the Share for the given String(having the same name, for instance). But that does What i needed.
It would be cleaner though to make it with Java Reflection, without having to create a new constructor. So if any one have an idea with a code more clever, I would be happy!

Categories

Resources