I'm trying to add static methods largest and smallest to the Measurable interface.
The methods should return the object with the largest or smallest measure (double) from an array of Measurable Country objects. I tried doing so in the interface, but someone recommended me using the Comparator interface. How can this be done by using the Measurable interface instead?
class Main {
public static void main(String args[]) {
Measurable[] countries = new Measurable[3];
countries[0] = new Country("Uruguay", 176220);
countries[1] = new Country("Thailand", 514000);
countries[2] = new Country("Belgium", 30510);
Measurable maximum = Measurable.largest(countries);
Measurable smallest = Measurable.smallest(countries);
}
}
class Country implements Measurable {
private String name;
private double area;
public Country(String name, double area) {
this.name = name;
this.area = area;
}
}
interface Measurable {
static Measurable largest(Measurable[] countries) {
public static Measurable largest(Measurable[]objects){
if (objects == null || objects.length == 0) {
return new Country("", 0);
}
Measurable max = new Country("", 0);
for (Measurable obj : objects) {
if (obj.getMeasure() > max.getMeasure()) {
max = obj;
}
}
return max;
}
}
static Measurable smallest(Measurable[] objects) {
if (objects == null || objects.length == 0) {
return new Country("", 0);
}
Measurable max = new Country("", 0);
for (Measurable obj : objects) {
if (obj.getMeasure() < min.getMeasure()) {
min = obj;
}
}
return min;
}
}
double getMeasure();
}
You don't need to create the Measurable interface if you want to use Comparator/Comparable.
Just implement Comparable in Country and then loop through the array to find min and max.
class Main {
public static void main(String args[]) {
Country[] countries = new Country[3];
countries[0] = new Country("Uruguay", 176220);
countries[1] = new Country("Thailand", 514000);
countries[2] = new Country("Belgium", 30510);
Country max = null;
Country min = null;
for (Country c : countries) {
if (max == null || max.compareTo(c) < 0) {
max = c;
}
if (min == null || min.compareTo(c) > 0) {
min = c;
}
}
System.out.printf("max: %s (%s)%n", max.name, max.area);
System.out.printf("min: %s (%s)%n", min.name, min.area);
}
}
class Country implements Comparable<Country> {
String name;
double area;
public Country(String name, double area) {
this.name = name;
this.area = area;
}
#Override
public int compareTo(Country other) {
// Returns int <0 if this is smaller than other
// 0 if they are equal
// int >0 if this is greater than other
return Double.compare(this.area, other.area);
}
}
If you put your countries in a collection you can use the Collections.min() and Collections.max() functions together with the Comparable interface. Your main method would then look like this:
public static void main(String args[]) {
List<Country> countries = new ArrayList<>();
countries.add(new Country("Uruguay", 176220));
countries.add(new Country("Thailand", 514000));
countries.add(new Country("Belgium", 30510));
Country max = Collections.max(countries);
Country min = Collections.min(countries);
System.out.printf("max: %s (%s)%n", max.name, max.area);
System.out.printf("min: %s (%s)%n", min.name, min.area);
}
If you still want to use the Measurable interface you can extend ArrayList and have that class implement it like this:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Main {
public static void main(String args[]) {
CountryList countries = new CountryList();
countries.add(new Country("Uruguay", 176220));
countries.add(new Country("Thailand", 514000));
countries.add(new Country("Belgium", 30510));
Country max = countries.getLargest();
Country min = countries.getSmallest();
System.out.printf("max: %s (%s)%n", max.name, max.area);
System.out.printf("min: %s (%s)%n", min.name, min.area);
}
}
class CountryList extends ArrayList<Country> implements Measurable{
#Override
public Country getSmallest() {
return Collections.min(this);
}
#Override
public Country getLargest() {
return Collections.max(this);
}
}
interface Measurable{
Country getSmallest();
Country getLargest();
}
class Country implements Comparable<Country> {
String name;
double area;
public Country(String name, double area) {
this.name = name;
this.area = area;
}
#Override
public int compareTo(Country o) {
return Double.compare(this.area, o.area);
}
}
Related
I am trying to make a new method that tells the user what the country with the highest point out of my array is. What I have currently done is inputted 2 country names followed by their highest point name and the number of the highest point, but now I am trying to output the one country that has the indefinite highest point, in my case from what i've added, its Argentina with Aconcagua as its highest point as 6960.
Code:
Main file:
public class continentTest
{
public static void main(String[] args) {
Continent southAmerica = new Continent();
Country southAmericanRepublic = new Country("Argentina", new HighestPoint("Aconcagua", 6960));
southAmerica.addCountry(southAmericanRepublic);
Country anotherSouthAmericanRepublic = new Country("Columbia", new HighestPoint("Pico Cristóbal Colón",5730));
southAmerica.addCountry(anotherSouthAmericanRepublic);
System.out.println (southAmerica.toString());
}
}
Other files:
class Country {
String name;
HighestPoint hp;
public Country (String nm, HighestPoint pt) {
name = nm;
hp = pt;
}
public String toString () {
return name + ": " + hp.toString() + "\n";
}
}
class HighestPoint {
String name;
int height;
public HighestPoint (String nm, int ht) {
name = nm;
height = ht;
}
public String toString () {
return name + " " + String.valueOf (height);
}
}
import java.util.*;
class Continent {
ArrayList<Country> countries;
public Continent () {
countries = new ArrayList<Country>();
}
public void addCountry (Country c) {
countries.add (c);
}
public String toString () {
String s = "";
for (Country c : countries)
s += c.toString();
return s;
}
}
I am not quite sure how to take the largest value from an array and display it along with the country name. Any help would be appreciated, thanks!
The following method in the continent class may help:
public Country getHighestPoint() {
int highest = 0;
Country temp;
for(int index = 0; index < countries.size(); index++) {
if(countries.get(index).hp.height > highest) {
highest = countries.get(index).hp.height
temp = countries.get(index)
}
}
return temp;
}
This exercise is a good opportunity to learn about the Comparable and Comparator
Starting with Comparable, you should apply this to your HighestPoint
class HighestPoint implements Comparable<HighestPoint> {
String name;
int height;
public HighestPoint (String nm, int ht) {
name = nm;
height = ht;
}
public String toString () {
return name + " " + String.valueOf (height);
}
public int compareTo(HighestPoint hp) {
return height - hp.height;
}
}
Now that's done, you can compare two HighestPoints and determine which is bigger.
Next: Comparator. We can use this with Continent, as you have a Collection (ArrayList) of all the Countries in a Content.
class Continent {
//... keep what is already in Continent
Comparator countryComparator = new Comparator<Country> () {
public int compare(Country a, Country b) {
return a.highestPoint.compareTo(b.highestPoint);
}
}
}
Now we can compare Countries and sort the array list by their HighestPoint
The reason it makes sense to use Comparable with HighestPoint and Comparator with your Countries array is that HighestPoint is a class defined with two data points: A name and a height. Whereas a Country could have many data points, and you could have many Comparators to sort Countries based on different criteria
You can solve it with Collections.
Country countryWithHighestPoint = Collections.max(southAmerica.countries, Comparator.comparing(s -> s.hp.height));
continentTest
import java.util.Collections;
import java.util.Comparator;
public class continentTest {
public static void main(String[] args) {
Continent southAmerica = new Continent();
Country southAmericanRepublic = new Country("Argentina", new HighestPoint("Aconcagua", 6960));
southAmerica.addCountry(southAmericanRepublic);
Country anotherSouthAmericanRepublic = new Country("Columbia", new HighestPoint("Pico Cristóbal Colón", 5730));
southAmerica.addCountry(anotherSouthAmericanRepublic);
Country countryWithHighestPoint = Collections.max(southAmerica.countries, Comparator.comparing(s -> s.getHighestPoint().getHeight()));
System.out.println(countryWithHighestPoint.toString());
System.out.println(southAmerica.toString());
}
}
Country
class Country {
private String name;
private HighestPoint hp;
public Country (String nm, HighestPoint pt) {
name = nm;
hp = pt;
}
public String toString () {
return name + ": " + hp.toString() + "\n";
}
public HighestPoint getHighestPoint()
{
return hp;
}
}
HighestPoint
class HighestPoint {
private String name;
private int height;
public HighestPoint (String nm, int ht) {
name = nm;
height = ht;
}
public String toString () {
return name + " " + String.valueOf (height);
}
public int getHeight()
{
return height;
}
}
Over here i'm trying to make use of an interface called "Measurable" with one method called getMeasure. The problem is, I'm trying to get the average height of all the people in my program, by accessing the method in my interface. One of the problems I can't access the getMeasure method for some reason, and at last get the average height of all the people in the array. How can I solve this problem?
class Main {
public static void main(String args[]) {
Person[] people = new Person[4];
people[0] = new Person("Larry", 65);
people[1] = new Person("Susan", 45);
people[2] = new Person("Joe", -45);
people[3] = new Person("", 0);
double averageHeight = average(people);
}
public static double average(Person[] objects)
{
if (objects.length == 0) { return 0; }
double sum = 0;
for (Person obj : objects)
{
double measure = obj.getMeasure();
sum = sum + measure;
}
double result = sum / objects.length;
return result;
}
}
interface Measurable {
double getMeasure();
}
public class Person {
private String name;
private Integer height;
public Person(String name, Integer height)
{
this.name = name;
this.height = height;
}
public double getMeasure() {
return height;
}
}
The Person class should implement Measurable:
public class Person implements Measurable {
...
}
Then if you want to make your average function reusable (I guess this is your desired outcome), you should replace the Person instance with Measurable:
public static double average(Measurable[] objects) {
...
for (Measurable obj : objects){
...
}
}
This way you could have different Measurable implementations to calculate the average.
public class Person implements Measurable {
private String name;
private Integer height;
public Person(String name, Integer height)
{
this.name = name;
this.height = height;
}
#Override
public double getMeasure() {
return height;
}
You have to implement the to use it. If the Interface also implements the method, you have to add the #Override modifier.
I just try to understand streams in Java and I stuck at sorting phase.
My purpose is to get most expensive vege pizza with one stream. At this point I get pizza price but I can't sort it. Can anyone tell me how I should do it ?
I try with this :
pizzas.stream()
.flatMap(pizza -> Stream.of(pizza.getIngredients())
.filter(list -> list.stream().noneMatch(Ingredient::isMeat))
.map(list -> list.stream().map(Ingredient::getPrice).reduce(0,(a, b) -> a + b))
.sorted((o1, o2) -> o1.intValue() - o2.intValue())
)
.forEach(System.out::println);
This code returns me unsorted values of pizza.
import java.util.Collection;
import java.util.Comparator;
interface Pizza {
interface Ingredient {
boolean isMeat();
int getPrice();
}
Collection<Ingredient> getIngredients();
static boolean isVegetarian(Pizza pizza) {
return pizza.getIngredients().stream().noneMatch(Ingredient::isMeat);
}
static int price(Pizza pizza) {
return pizza.getIngredients().stream().mapToInt(Ingredient::getPrice).sum();
}
static Pizza mostExpensiveVegetarianPizza(Collection<Pizza> pizzas) {
return pizzas.stream()
.filter(Pizza::isVegetarian)
.max(Comparator.comparingInt(Pizza::price))
.orElseThrow(() -> new IllegalArgumentException("no veggie pizzas"));
}
}
If you want Ingredient.getPrice() to return a double, you would use Stream.mapToDouble() in Pizza.price() and Comparator.comparingDouble() in Pizza.mostExpensiveVegetarianPizza().
To find the pizza with the highest price you need to either compute the price of each pizza every time the prices are compared or have an object that stores both the pizza and the price.
Here's a solution that uses an anonymous object to hold the temporary state where we need both the pizza and its price:
Optional<Pizza> pizza = pizzas.stream()
.filter(p -> p.getIngredients().stream()
.noneMatch(Ingredient::isMeat)) // filter
.map(p -> new Object() { // anonymous object to hold (pizza, price)
Pizza pizza = p; // store pizza
int price = p.getIngredients().stream()
.mapToInt(Ingredient::getPrice).sum(); // store price
})
.max(Comparator.comparingInt(o -> o.price)) // find the highest price
.map(o -> o.pizza); // get the corresponding pizza
I've made a short functional example. I have encapsulated some streams inside Pizza class to improve legibility.
INGREDIENT
public class Ingredient {
private String name;
private double price;
private boolean meat;
public Ingredient(String name, double price, boolean meat) {
this.name = name;
this.price = price;
this.meat = meat;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isMeat() {
return meat;
}
public void setMeat(boolean meat) {
this.meat = meat;
}
}
PIZZA
public class Pizza {
private String name;
private List<Ingredient> ingredients;
public Pizza(String name, List<Ingredient> ingredients) {
this.name = name;
this.ingredients = ingredients;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Ingredient> getIngredients() {
return ingredients;
}
public void setIngredients(List<Ingredient> ingredients) {
this.ingredients = ingredients;
}
public boolean isVegan() {
return (ingredients != null) ? ingredients.stream().noneMatch(Ingredient::isMeat)
: false;
}
public double getTotalCost() {
return (ingredients != null) ? ingredients.stream().map(Ingredient::getPrice)
.reduce(0.0, Double::sum)
: 0;
}
#Override
public String toString() {
return "Pizza [name=" + name + "; cost=" + getTotalCost() +"$]";
}
}
MAIN
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class VeganPizzaPlace {
public static void checkMostExpensiveVeganPizza(List<Pizza> pizzas) {
if (pizzas != null) {
Optional<Pizza> maxVegan =
pizzas.stream()
.filter(Pizza::isVegan)
.max(Comparator.comparingDouble(Pizza::getTotalCost));
if (maxVegan.isPresent()) {
System.out.println(maxVegan.get().toString());
} else {
System.out.println("No vegan pizzas in the menu today");
}
}
}
public static void main (String[] args) {
List<Pizza> pizzas = new ArrayList<Pizza>();
Ingredient tomato = new Ingredient("tomato", 0.50, false);
Ingredient cheese = new Ingredient("cheese", 0.75, false);
Ingredient broccoli = new Ingredient("broccoli", 50.00, false);
Ingredient ham = new Ingredient("ham", 10.00, true);
List<Ingredient> ingredientsMargherita = new ArrayList<Ingredient>();
ingredientsMargherita.add(tomato);
ingredientsMargherita.add(cheese);
Pizza margherita = new Pizza("margherita", ingredientsMargherita);
List<Ingredient> ingredientsSpecial = new ArrayList<Ingredient>();
ingredientsSpecial.add(tomato);
ingredientsSpecial.add(cheese);
ingredientsSpecial.add(broccoli);
Pizza special = new Pizza("special", ingredientsSpecial);
List<Ingredient> ingredientsProsciutto = new ArrayList<Ingredient>();
ingredientsProsciutto.add(tomato);
ingredientsProsciutto.add(cheese);
ingredientsProsciutto.add(ham);
Pizza prosciutto = new Pizza("prosciutto", ingredientsProsciutto);
pizzas.add(margherita);
pizzas.add(special);
pizzas.add(prosciutto);
checkMostExpensiveVeganPizza(pizzas);
}
}
OUTPUT
Pizza [name=special; cost=51.25$]
If you do not like clean code, you can use instead
Optional<Pizza> maxVegan =
pizzas.stream()
.filter(p -> p.getIngredients().stream().noneMatch(Ingredient::isMeat))
.reduce((p1, p2) -> p1.getIngredients().stream().map(Ingredient::getPrice).reduce(0.0, Double::sum)
< p2.getIngredients().stream().map(Ingredient::getPrice).reduce(0.0, Double::sum) ? p1 : p2);
EDIT: Expression for selecting max valued pizza using a reduce is based on listing 5.8 (page 110) from the book "Java 8 in action" by Urma, Fusco and Mycroft. A great book! :-)
I have an assignment to make this Restaurant Program. it Consists of an Order Class a product class and the main class. Order has an ArrayList to hold the products. I create an instance of the Order and then I add items through my main method.A product has a name(string) a bar-code(string), and a price(float).
Then I have to output a receipt.But what if a customer orders more of one product? Do I instantiate everything one by one? Is a second Beer Product independent? Should I hold quantities somehow? If I want to add a second beer I have to create a new product Beer2 etc? I don't know beforehand how many products each order will hold and the quantity of each so Is this way of instantiating proper? Thanks
Note: it is still incomplete as I want to deal with this before I move on.
import java.util.Date;
public class MyRestaurantTester {
public static void main(String[] args) {
Date currentDate = new Date();
Paraggelia order1 = new Paraggelia(currentDate,"11B");
Product Beer = new Product("Amstel","111222",1.20f);
Product Beef = new Product("Pork Beef","333444",8.50f);
order1.add(Beer);
order1.add(Beef);
System.out.println(order1.getReceipt(30f));
}
}
Order Class(nevermind the name Paraggelia I gave it)
import java.util.ArrayList;
import java.util.Date;
/*Notes to self:
* -Work on Comments
* -Javadocs maybe?
* -try to optimize the rough code.
*/
/*Order class*/
public class Paraggelia {
private Date orderDate;
private String tableNumber;
private int customerCount;
private ArrayList<Product> listOfItems;
/*Constructor(s)*/
Paraggelia(Date orderDate,String tableNumber){
this.orderDate=orderDate;
this.tableNumber=tableNumber;
this.listOfItems = new ArrayList<Product>();
}
/*Add && Delete Products from the Order class*/
public void add(Product p){
if(p == null)
{
throw new IllegalArgumentException();
}else{
listOfItems.add(p);
}
}
public void delete(Product p){
if(p == null)
{
throw new IllegalArgumentException();
}
else
{
listOfItems.remove(p);
}
}
/** Calculates and returns the total price
* Usually called directly as a parameter of getReceipt function
* */
public static float getTotalPrice(){
return 0;
}
/** Creates and returns the final Receipt!
* -Display must consist of:
* Item$ - BarCode# - Item Amount#
* Total Price#
* Table Number#
*/
public String getReceipt(float totalPrice){
StringBuilder receipt = new StringBuilder();
for(int i =0; i<this.listOfItems.size();i++){
receipt.append(listOfItems.get(i).getName());
receipt.append("\n");
}
return new String(receipt);
}
/*Getters && Setters */
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
public String getTableNumber() {
return tableNumber;
}
public void setTableNumber(String tableNumber) {
this.tableNumber = tableNumber;
}
public int getCustomerCount() {
return customerCount;
}
public void setCustomerCount(int customerCount) {
this.customerCount = customerCount;
}
}
Product Class:
public class Product {
private String Name;
private String barCode;
private float sellingPrice;
/*Constructors: */
Product(){}
Product(String Name,String barCode,float sellingPrice){
this.Name=Name;
this.barCode=barCode;
this.sellingPrice=sellingPrice;
}
/*Getters & Setters*/
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getBarCode() {
return barCode;
}
public void setBarCode(String barCode) {
this.barCode = barCode;
}
public float getSellingPrice() {
return sellingPrice;
}
public void setSellingPrice(float sellingPrice) {
this.sellingPrice = sellingPrice;
}
}
Instead of ArrayList ( List ) you can use Map ( HashMap for example )
MyRestaurantTester
public class MyRestaurantTester {
public static void main(String[] args) {
Date currentDate = new Date();
Paraggelia order1 = new Paraggelia(currentDate,"11B");
Product Beer = new Product("Amstel","111222",1.20f);
Product Beef = new Product("Pork Beef","333444",8.50f);
order1.add(Beer, 1);
order1.add(Beef, 5);
System.out.println(order1.getReceipt(30f));
}
}
Paraggelia
class Paraggelia {
private Date orderDate;
private String tableNumber;
private int customerCount;
private Map<Product, Integer> listOfItems;
/*Constructor(s)*/
Paraggelia(Date orderDate,String tableNumber){
this.orderDate=orderDate;
this.tableNumber=tableNumber;
this.listOfItems = new HashMap<Product, Integer>();
}
/*Add && Delete Products from the Order class*/
public void add(Product p, int quantity){
if(p == null)
{
throw new IllegalArgumentException();
}else{
listOfItems.put(p, quantity);
}
}
public void delete(Product p){
if(p == null)
{
throw new IllegalArgumentException();
}
else
{
listOfItems.remove(p);
}
}
/** Calculates and returns the total price
* Usually called directly as a parameter of getReceipt function
* */
public static float getTotalPrice(){
return 0;
}
/** Creates and returns the final Receipt!
* -Display must consist of:
* Item$ - BarCode# - Item Amount#
* Total Price#
* Table Number#
*/
public String getReceipt(float totalPrice){
StringBuilder receipt = new StringBuilder();
for(Map.Entry<Product,Integer> entry : this.listOfItems.entrySet()) {
Product product = entry.getKey();
Integer quantity = entry.getValue();
receipt.append(product.getName() + " " + quantity);
receipt.append("\n");
}
return new String(receipt);
}
/*Getters && Setters */
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
public String getTableNumber() {
return tableNumber;
}
public void setTableNumber(String tableNumber) {
this.tableNumber = tableNumber;
}
public int getCustomerCount() {
return customerCount;
}
public void setCustomerCount(int customerCount) {
this.customerCount = customerCount;
}
}
OUTPUT:
Pork Beef 5
Amstel 1
Three basic approaches come to mind:
Instantiate each product individually
Instead of ArrayList, have another structure that can associate items with quantities; or,
Make a class Article, which belongs to a Product: Product beerProduct = new Product("beer", "0129", 1.37); Article beer = new Article(beerProduct), beer2 = new Article(beerProduct).
The first solution gives you a lot of flexibility (e.g. to discount individual articles for, say, being damaged). The second solution is more economical with objects. The third one captures the intuition that all the Heineken bottles are the same. It is really up to what you want to do - both approaches are equally valid, for some purpose.
In my portfolio application I have a table with stock title and portfolio weight. For each stock title I'm downloading prices for a specific time window. Now I'm trying to calculate the average portfolio rate return.
Formula per day:
Ypf(d) = (W1 * Y1(d)) + (W2 * Y2(d)) + … + (Wn * Yn(d))
Formula Portfolio:
(Ypf(1) + Ypf(2) + ... + Ypf(dn)) / n
> W1 = weight of 1st stock in table
> W2 = weight of 2nd stock in table
> Y1 = yield of 1st stock in table
> Y2 = yield of 2nd stock in table
> d = current day n = total days
I am stuck here and seeking for help....
public void calcAvgYield() {
for (Stock s : pfTable.getItems()) {
// get list of prices for stock title
List<Double> vl = s.getValue();
// new list for calculated yield
List<Double> yl = null;
// get weight for stock title
int w = s.getWeight();
// get list size
int i = vl.size()-1;
// calculate yield for each day and fill new list with results
while (i > 0) {
yl.add(((s.getValue().get(i) - s.getValue().get(i-1)) / s.getValue().get(i-1)) * 100);
i--;
}
}
}
Stock class:
public class Stock {
private final SimpleStringProperty symbol = new SimpleStringProperty();
private final SimpleIntegerProperty weight = new SimpleIntegerProperty();
private List<Double> value = new ArrayList<Double>();
private List<String> date = new ArrayList<String>();
public String getSymbol() {
return symbol.get();
}
public void setSymbol(String symbol) {
this.symbol.set(symbol);
}
public Integer getWeight() {
return weight.get();
}
public void setWeight(Integer weight) {
this.weight.set(weight);
}
public List<Double> getValue() {
return value;
}
public void setValue(ArrayList<Double> value) {
this.value = value;
}
}
Thanks.
Java's an object-oriented language. Why don't you use objects and encapsulation to better advantage? I think your problem is that you haven't abstracted the problem very well.
I'd expect to see a Stock class, not Lists of doubles. A Portfolio would have a Map of stock, shares pairs.
A Stock might have a Map of date, value pairs.
How do you calculate the weights? Are they fractions of shares in the Portfolio?
Let the Portfolio calculate the current rate of return in a method by iterating over its Map of Stocks.
Here's how I'd do it. I think there are still subtleties to be sorted out with number of shares, because your position can evolve over time. A Map of Stock and shares, with Stock carrying prices over time, is insufficient. But this will give you the idea.
Stock.java
package stock;
import utils.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Stock abstraction
* #author Michael
* #link https://stackoverflow.com/questions/24417246/yield-calculation/24430415
* #since 6/26/2014 6:22 PM
*/
public class Stock implements Comparable<Stock> {
private final String symbol;
private final String companyName;
private Map<Date, Double> prices;
public Stock(String symbol, String companyName) {
if (StringUtils.isBlankOrNull(symbol)) throw new IllegalArgumentException("symbol cannot be blank or null");
if (StringUtils.isBlankOrNull(companyName)) throw new IllegalArgumentException("company name cannot be blank or null");
this.symbol = symbol;
this.companyName = companyName;
this.prices = new ConcurrentHashMap<Date, Double>();
}
public String getSymbol() {
return symbol;
}
public String getCompanyName() {
return companyName;
}
public void addPrice(Date date, double price) {
if (date == null) throw new IllegalArgumentException("date cannot be null");
if (price < 0.0) throw new IllegalArgumentException("price cannot be negative");
this.prices.put(date, price);
}
public void removePrice(Date date) {
if (date != null) {
this.prices.remove(date);
}
}
public synchronized Double getPrice(Date date) {
double price = 0.0;
if (this.prices.containsKey(date)) {
price = this.prices.get(date);
} else {
price = interpolatePrice(date);
}
return price;
}
private Double interpolatePrice(Date date) {
double price = 0.0;
if (this.prices.size() > 0) {
List<Date> dates = new ArrayList<Date>(this.prices.keySet());
Collections.sort(dates, new DateComparator());
if (date.before(dates.get(0))) {
price = this.prices.get(dates.get(0));
} else if (date.after(dates.get(dates.size()-1))) {
price = this.prices.get(dates.get(dates.size()-1));
} else {
for (int i = 1; i < dates.size(); ++i) {
if (dates.get(i).after(date)) {
Date d1 = dates.get(i-1);
double p1 = this.prices.get(d1);
Date d2 = dates.get(i);
double p2 = this.prices.get(d2);
double fraction = ((double)(date.getTime()-d1.getTime())/(d2.getTime()-d1.getTime()));
price = p1 + fraction*(p2-p1);
}
}
}
}
return price;
}
public boolean hasDate(Date date) {
return this.prices.containsKey(date);
}
public int getNumPrices() {
return this.prices.size();
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Stock stock = (Stock) o;
return symbol.equals(stock.symbol);
}
#Override
public int hashCode() {
return symbol.hashCode();
}
#Override
public int compareTo(Stock other) {
return this.symbol.compareTo(other.symbol);
}
#Override
public String toString() {
return this.symbol;
}
}
class DateComparator implements Comparator<Date> {
#Override
public int compare(Date that, Date another) {
if (that.before(another)) {
return -1;
} else if (that.after(another)) {
return +1;
} else {
return 0;
}
}
}
Portfolio.java:
package stock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Portfolio is a collection of Stocks
* #author Michael
* #link https://stackoverflow.com/questions/24417246/yield-calculation/24430415
* #since 6/26/2014 6:31 PM
*/
public class Portfolio {
private Map<Stock, Integer> stocks;
public Portfolio() {
this.stocks = new ConcurrentHashMap<Stock, Integer>();
}
public void addStock(Stock stock, int numShares) {
if (stock == null) throw new IllegalArgumentException("stock cannot be null");
this.stocks.put(stock, numShares);
}
public void addStock(Stock stock) {
addStock(stock, 1);
}
public void updateShares(Stock stock, int numShares) {
if (numShares <= 0) throw new IllegalArgumentException("numShares must be greater than zero");
if (stock != null) {
this.stocks.put(stock, numShares);
}
}
public void removeStock(Stock stock) {
if (stock != null) {
this.stocks.remove(stock);
}
}
public boolean containsSymbol(String symbol) {
return this.getPortfolioSymbols().contains(symbol);
}
public int getNumShares(String symbol) {
int numShares = 0;
if (this.getPortfolioSymbols().contains(symbol)) {
numShares = this.stocks.get(new Stock(symbol, "Dummy Company Name"));
}
return numShares;
}
public int getNumStocks() {
return this.stocks.size();
}
public List<String> getPortfolioSymbols() {
List<String> symbols = new ArrayList<String>(this.stocks.size());
for (Stock stock : stocks.keySet()) {
symbols.add(stock.getSymbol());
}
Collections.sort(symbols);
return symbols;
}
public double calculateValue(Date date) {
double value = 0.0;
if (date != null) {
for (Stock stock : this.stocks.keySet()) {
value += stock.getPrice(date)*this.stocks.get(stock);
}
}
return value;
}
}
Here's how you unit test a Java class. I've also written a JUnit test for Portfolio, but I won't post it now.
StockTest.java:
package stock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* PortfolioTest JUnit test for Portfolio
* #author Michael
* #link https://stackoverflow.com/questions/24417246/yield-calculation/24430415
* #since 6/26/2014 8:33 PM
*/
public class PortfolioTest {
private static final String DATE_PATTERN = "yyyy-MMM-dd";
private static final DateFormat DATE_FORMAT;
private static final double TOLERANCE = 0.001;
static {
DATE_FORMAT = new SimpleDateFormat(DATE_PATTERN);
DATE_FORMAT.setLenient(false);
}
private Portfolio portfolio;
#Before
public void setUp() throws ParseException {
this.portfolio = new Portfolio();
Stock testStock = new Stock("AAPL", "Apple Inc");
testStock.addPrice(DATE_FORMAT.parse("2014-Jun-02"), 89.807);
testStock.addPrice(DATE_FORMAT.parse("2014-Jun-04"), 92.117);
this.portfolio.addStock(testStock, 100);
testStock = new Stock("ORCL", "Oracle Corporation");
testStock.addPrice(DATE_FORMAT.parse("2014-Jun-02"), 41.97);
testStock.addPrice(DATE_FORMAT.parse("2014-Jun-04"), 41.70);
this.portfolio.addStock(testStock, 1000);
}
#Test
public void testPortfolio_Setup() {
List<String> expectedSymbols = Arrays.asList("AAPL", "ORCL");
Assert.assertEquals(expectedSymbols, this.portfolio.getPortfolioSymbols());
for (String symbol : expectedSymbols) {
Assert.assertTrue(this.portfolio.containsSymbol(symbol));
}
Assert.assertEquals(expectedSymbols.size(), portfolio.getNumStocks());
Assert.assertFalse(this.portfolio.containsSymbol("UTX"));
}
#Test
public void testRemoveStock_ContainsStock() {
int expectedSize = 2;
Assert.assertEquals(expectedSize, portfolio.getNumStocks());
Stock testStock = new Stock("AAPL", "Apple Inc");
this.portfolio.removeStock(testStock);
Assert.assertEquals(expectedSize - 1, portfolio.getNumStocks());
}
#Test
public void testRemoveStock_DoesNotContainStock() {
int expectedSize = 2;
Assert.assertEquals(expectedSize, portfolio.getNumStocks());
Stock testStock = new Stock("UTXL", "United Technologies Corporation");
this.portfolio.removeStock(testStock);
Assert.assertEquals(expectedSize, portfolio.getNumStocks());
}
#Test
public void testGetNumShares_ContainsSymbol() {
Map<String, Integer> expected = new HashMap<String, Integer>() {{
put("AAPL", 100);
put("ORCL", 1000);
}};
for (String symbol : expected.keySet()) {
Assert.assertTrue(expected.get(symbol) == portfolio.getNumShares(symbol));
}
}
#Test
public void testGetNumShares_DoesNotContainSymbol() {
Assert.assertEquals(0, portfolio.getNumShares("UTX"));
}
#Test
public void testCalculateValue_BeforeFirstDate() throws ParseException {
Date testDate = DATE_FORMAT.parse("2014-Jun-02");
double expected = 89.807*100 + 41.97*1000;
double actual = portfolio.calculateValue(testDate);
Assert.assertEquals(expected, actual, TOLERANCE);
}
#Test
public void testCalculateValue_AfterLastDate() throws ParseException {
Date testDate = DATE_FORMAT.parse("2014-Jul-04");
double expected = 92.117*100 + 41.70*1000;
double actual = portfolio.calculateValue(testDate);
Assert.assertEquals(expected, actual, TOLERANCE);
}
#Test
public void testCalculateValue_Interpolate() throws ParseException {
Date testDate = DATE_FORMAT.parse("2014-Jun-03");
double expected = 90.962*100 + 41.835*1000;
double actual = portfolio.calculateValue(testDate);
Assert.assertEquals(expected, actual, TOLERANCE);
}
#Test
public void testUpdateShares() {
Stock testStock = new Stock("ORCL", "Oracle Corporation");
Assert.assertEquals(1000, this.portfolio.getNumShares("ORCL"));
this.portfolio.updateShares(testStock, 10);
Assert.assertEquals(10, this.portfolio.getNumShares("ORCL"));
}
}
I think you need to initialize your list. Try:
List<Double> yl = new ArrayList<Double>();
Currently, it's null, which may be giving you the problem.
Put this
List<Double> yl = null;
before the
for (Stock s : pfTable.getItems()) {
loop.