Why is this an unreachable statement? [closed] - java

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Towards the bottom of this code I am getting an "unreachable statement" error. I have tried a few things, but cannot figure out why this is happening. The error is towards the bottom of the code (I have commented with // where the error is) Please help point me in the right direction I'm stumped!
/**
* Describes a certain model.
*
* #author (Joshua Baker)
* #version (1.0)
*/
public class Model
{
public static final int IN_PER_FOOT = 12;
public static final int BASE_RATE = 60;
public static final int TALL_INCHES = 67;
public static final double THIN_POUNDS = 140.0;
public static final int TALL_THIN_BONUS = 5;
public static final int TRAVEL_BONUS = 4;
public static final int SMOKER_DEDUCTION = 10;
private String firstName;
private String lastName;
private int heightInInches;
private double weightInPounds;
private boolean travel;
private boolean smokes;
private String newHeight;
private int perHourRate;
/**
* Default constructor
*/
public Model()
{
setFirstName ("");
setLastName ("");
setHeightInInches (0);
setWeightInPounds (0.0);
setTravel (false);
setSmokes (false);
}
/**
*
*/
public Model (String whatIsFirstName, String whatIsLastName, int whatIsHeight, double whatIsWeight,
boolean canTravel, boolean smoker)
{
setFirstName (whatIsFirstName);
setLastName (whatIsLastName);
setHeightInInches (whatIsHeight);
setWeightInPounds (whatIsWeight);
setTravel (canTravel);
setSmokes (smoker);
}
/**
*#return first name
*/
public String getFirstName()
{
return firstName;
}
/**
*#return last name
*/
public String getLastName()
{
return lastName;
}
/**
*#return height in inches
*/
public int getHeightInInches()
{
return heightInInches;
}
/**
*#return the converted height
*/
public String getNewHeight()
{
return newHeight;
}
/**
*#return weight in pounds
*/
public double getWeightInPounds()
{
return weightInPounds;
}
/**
*#return models pay per hour rate
*/
public int getPerHourRate()
{
return perHourRate;
}
/**
*#return travel
*/
public boolean getTravel()
{
return travel;
}
/**
*#return smokes
*/
public boolean getSmokes()
{
return smokes;
}
/**
* models first name
*/
public void setFirstName(String whatIsFirstName)
{
firstName = whatIsFirstName;
}
/**
* models last name
*/
public void setLastName(String whatIsLastName)
{
lastName = whatIsLastName;
}
/**
* models height in inches
*/
public void setHeightInInches(int whatIsHeight)
{
if (whatIsHeight >0){
heightInInches = whatIsHeight;
}
}
/**
* models weight in pounds
*/
public void setWeightInPounds(double whatIsWeight)
{
if (whatIsWeight >0){
weightInPounds = whatIsWeight;
}
}
/**
* can model travel
*/
public void setTravel(boolean canTravel)
{
travel = canTravel;
}
/**
* does model smoke
*/
public void setSmokes(boolean smoker)
{
smokes = smoker;
}
/**
* Converts to feet and inches
*/
public String convertheightToFeetInches()
{
int leftOver = (heightInInches %= IN_PER_FOOT);
int newHeight = (heightInInches % IN_PER_FOOT);
return newHeight + "Foot" + leftOver + "Inches";
}
/**
*
*/
public int calculatePayPerHour(){
if (heightInInches >= TALL_INCHES && (weightInPounds <= THIN_POUNDS)) {
perHourRate = BASE_RATE + TALL_THIN_BONUS;
return perHourRate;
}
else
{
perHourRate = BASE_RATE;
return perHourRate;
}
if (travel) { //unreachable statement
perHourRate = BASE_RATE + TRAVEL_BONUS;
return perHourRate;
}
else
{
perHourRate = BASE_RATE;
return perHourRate;
}
if (smokes) { //unreachable statement
perHourRate = BASE_RATE - SMOKER_DEDUCTION;
return perHourRate;
}
else {}
}
/**
* Displays details
*/
public void displayInfo()
{
System.out.print("Name : " + getFirstName() + " ");
System.out.println(getLastName());
System.out.println("Height : " + getNewHeight() + "inches");
System.out.println("Weight : " + getWeightInPounds() + "pounds");
System.out.print("Travel : " + getTravel() + " " );
System.out.print("Smokes : " + getSmokes() );
System.out.println("Hourly rate : " + getPerHourRate() );
}
}

That is because your program will return from either your first if block or the corresponding else block: -
if (heightInInches >= TALL_INCHES && (weightInPounds <= THIN_POUNDS)) {
perHourRate = BASE_RATE + TALL_THIN_BONUS;
return perHourRate;
}
else
{
perHourRate = BASE_RATE;
return perHourRate;
}
System.out.println("This will never get printed. And will show compiler error");
So, either of the two return statement will be executed. And hence any further code is unreachable.
Seems that you want to have cumulative sum of all the service rates to get the final perHourRate, for that, you can remove the return statement from each of the if-else block. And then for all the if-else block after the first one, instead of assigning the current price to perHourRate, do a compound addition +=.
Also, since you are working on the instance field - perHourRate, you don't need to return it at all. The changes you did on perHourRate can be obtained using getPerHourRate(). So, change the return type to void.
May you can try updating your calculatePayPerHour method to the one below:
public void calculatePayPerHour(){
if (heightInInches >= TALL_INCHES && (weightInPounds <= THIN_POUNDS)) {
perHourRate = BASE_RATE + TALL_THIN_BONUS; // Initial assignment
} else {
perHourRate = BASE_RATE; // Initial assignment
}
/** Rest of the assignment will be compound assignment, since you
are now updating the `perHourRate` **/
if (travel) {
perHourRate += TRAVEL_BONUS;
} // You don't need an else now. Since BASE_RATE is already added
if (smokes) {
perHourRate -= SMOKER_DEDUCTION;
}
}

Inside your calculatePayPerHour method you have an if/else and the statement will never be reached because in both cases you are returning a result:
if (heightInInches >= TALL_INCHES && (weightInPounds <= THIN_POUNDS)) {
perHourRate = BASE_RATE + TALL_THIN_BONUS;
return perHourRate; // you return in the if
}
else
{
perHourRate = BASE_RATE;
return perHourRate; // you return in the else
}
... the execution will never reach here

if (heightInInches >= TALL_INCHES && (weightInPounds <= THIN_POUNDS)) {
perHourRate = BASE_RATE + TALL_THIN_BONUS;
return perHourRate; // <------------
}
else
{
perHourRate = BASE_RATE;
return perHourRate; // <------------
}
Regardless of your height or weight, one of these 2 returns will trigger, so any statement after it will never be executed. This is identical to the below code.
if (heightInInches >= TALL_INCHES && (weightInPounds <= THIN_POUNDS)) {
perHourRate = BASE_RATE + TALL_THIN_BONUS;
}
else
{
perHourRate = BASE_RATE;
}
return perHourRate;
//unreachable

in the if/else above the code you have 2 return statements already...
This means it will never reach the code below this..

In your method public int calculatePayPerHour() the first if else statement is returning a value in any case (in both if and else block).
If you dry run the program you will see that the control flow will never reach statements below this block hence your exception.

Related

Unexpected exception expected <nameoftheclass> but was <java.lang.AssertionError>

i don´t know how to pass this test. I tried every solution i thought of and didnt find a solution on the internet neither. Its my exam to school.
So, I have this class MojeException.java:
public class MojeException extends RuntimeException {
/**
* Creates a new instance of <code>NewException</code> without detail
* message.
*/
public MojeException() throws AssertionError{
}
/**
* Constructs an instance of <code>NewException</code> with the specified
* detail message.
*
* #param msg the detail message.
*/
public MojeException(String msg) throws AssertionError {
super(msg);
}
}
And i have this test:
#Test(expected = MojeException.class)
public void testKonstruktor11() {
Rozmer rozmer = new Rozmer(0, 0, 0);
fail() ;
}
The error i got is "Unexpected exception, expected but was<java.lang.AssertionError>"
The main class is this, however i dont know if its not irelevant:
public class Rozmer {
public static final double DIMENZE_MAX = 100;
public static final double DIMENZE_MIN = .1;
private static final double TO_CM = 100.00;
private final long delka;
private final long sirka;
private final long vyska;
public Rozmer(double delka, double sirka, double vyska){
this.delka = (long)(delka * TO_CM);
this.sirka = (long) (sirka * TO_CM);
this.vyska = (long) (vyska * TO_CM);
}
public double getDelka() {
return delka/TO_CM;
}
public double getSirka() {
return sirka/TO_CM;
}
public double getVyska() {
return vyska/TO_CM;
}
#Override
public String toString() {
return "Rozmer{" + "delka= " + delka/TO_CM + "0,sirka= " + sirka/TO_CM + "0,vyska= " + vyska/TO_CM + "0}";
}
#Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + (int) (this.delka ^ (this.delka >>> 32));
hash = 89 * hash + (int) (this.sirka ^ (this.sirka >>> 32));
hash = 89 * hash + (int) (this.vyska ^ (this.vyska >>> 32));
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Rozmer other = (Rozmer) obj;
if (this.delka != other.delka) {
return false;
}
if (this.sirka != other.sirka) {
return false;
}
if (this.vyska != other.vyska) {
return false;
}
return true;
}
public static boolean kontrolaDimenze(double dimenze) {
return DIMENZE_MIN <= dimenze && dimenze<=DIMENZE_MAX;
}
Thanks for all your ideas and solutions :)
Basically, you are instructing JUnit that in your test you expect that a MojeException (which is a RuntimeException) will be eventually thrown, and that it's not done by fail(), which instead throws an AssertionException, so a total different one.
So, you have to throw that specific exception somewhere, otherwise your test will always fail.
The best point to do that is possibly in your constructor, because it's the only method you invoked in the test, so it looks like you are testing that specific constructor. Maybe after checking one of the input parameters, which doesn't match an expected value, you can throw your exception.
Here is just an example of how you can modify your Rozmer class constructor:
public Rozmer(double delka, double sirka, double vyska) throws MojeException {
if(delka == 0.0 || sirka == 0.0 || vyska == 0.0) {
throw new MojeException("Unsupported value for delka, sirka or vyska");
}
this.delka = (long)(delka * TO_CM);
this.sirka = (long) (sirka * TO_CM);
this.vyska = (long) (vyska * TO_CM);
}
Then remove the fail() from your test.

How to invoke ParkingTicket(parker, parkee)?

Here is my problem I can't seem to figure out how to invoke a ParkingTicket object if (carMinutesPaid>meterMinutesPaid)? can any one help here are the details below to the question.
public static ParkingTicket checkParking(int carMinutesParked, int meterMinutesPaid)
{
Car parker = carMinutesParked;
ParkingMeter parkee = parkee;
if(carMinutesParked>meterMinutesPaid){
return new ParkingTicket(parker, parkee);
}
else if(carMinutesParked<=meterMinutesPaid){
System.out.println("null");
}
return new ParkingTicket(parker, parkee);
}
Here is the question for my project.
Remember, this method must be able to be used without a ParkingTicket object in existence.
Using a Car parameter and a ParkingMeter parameter, decide whether a ParkingTicket object should be created.
Invoke ParkingTicket(parker, parkee) if a ticket was merited, and return the result.
Return null if a ticket was not merited.
Here is my car class:
/**
* This is a Car class for Impark.
*
* #author Tre
* #version 2.0 15 October 2015
*/
public class Car
{
private static final int MINIMUM_PLATE_LENGTH=2;
private static final int MAXIMUM_PLATE_LENGTH=7;
public static final char MANUAL_TRANSMISSION='m';
public static final char AUTOMATIC_TRANSMISSION='a';
private static int defaultMinutesParked = 0;
private static double defaultOdometerInKm = 50000.5;
private String licensePlate;
private char transmissionType;
private double odometerInKm;
private int minutesParked;
/**
* #param newProposedLicensePlate the license plate of the car can equal null
* but must be between MINIMUM_PLATE_LENGTH and MAXIMUM_PLATE_LENGTH
*/
public Car(String newProposedLicensePlate)
{
setLicensePlate(newProposedLicensePlate);
transmissionType = AUTOMATIC_TRANSMISSION;
odometerInKm = defaultOdometerInKm;
minutesParked = defaultMinutesParked;
}
/**
* #return the license plate of the car can equal null
* but must be between MINIMUM_PLATE_LENGTH and MAXIMUM_PLATE_LENGTH
*/
public String getLicensePlate()
{
return licensePlate;
}
/**
* #return the transmission type MANUAL_TRANSMISSION or AUTOMATIC_TRANSMISSION
*/
public char getTransmissionType()
{
return transmissionType;
}
/**
* #return the odometer in kilometers
*/
public double getOdometerInKm()
{
return odometerInKm;
}
/**
* Recieve the license plate
* Mutator.licensePlate.
* #param proposedLicense String Conforming to ICBC *length* guidlines:
* http://www.icbc.com/vehicle-registration/license-plates/Pages/Personalized-licence-plates.aspx
* May also be null. The null represents a car without a plate
* If validation fails, null will be set.
*/
public void setLicensePlate(String proposedLicense)
{
if(proposedLicense==null){
licensePlate = proposedLicense;
}
else if(proposedLicense.length()>=MINIMUM_PLATE_LENGTH && proposedLicense.length()<=MAXIMUM_PLATE_LENGTH){
licensePlate = proposedLicense;
}
else{
licensePlate = null;
}
}
/**
* #param mOrA recieve the transmission type MANUAL_TRANSMISSION or AUTOMATIC_TRANSMISSION
* if invalid type of transmission is entered then will return "Installation failure: 'mOrA' is not a vaild transmission type"
*/
public void setTransmissionType(char mOrA)
{
if(mOrA==MANUAL_TRANSMISSION){
transmissionType = mOrA;
}
else if(mOrA==AUTOMATIC_TRANSMISSION){
transmissionType = mOrA;
}
else if (mOrA==mOrA){
System.out.println("Installation failure:" + " " + ("'")+(mOrA)+("'") + " " + "is not a valid transmission type.");
}
else{
transmissionType = mOrA;
}
}
/**
* #return the value of the odometer in with the String kilometers
*/
public String readOdometer()
{
return odometerInKm + " " + "kilometers";
}
/**
* #return the false if the minutesParked equals zero; otherwise true
*/
public boolean isParked()
{
if(minutesParked==defaultMinutesParked){
return false;
}
else{
return true;
}
}
/**
* #param duration replaces any existing value in minutesParked with the value from duration
*/
public void park(int duration)
{
if(duration>=defaultMinutesParked){
minutesParked = duration;
}
}
/**
* #param aOdometerInKm recieve the odometer in kilometers
*/
public void setOdometerInKm(double aOdometerInKm)
{
odometerInKm = aOdometerInKm;
}
/**
* #param aMinutesParked recieve the minutes parked in the stall but can not be a negative number
* if invalid number of minutes is entered then the number of minutes will not change.
*/
public void setMinutesParked(int aMinutesParked)
{
if(aMinutesParked>=defaultMinutesParked){
minutesParked = aMinutesParked;
}
else{
return;
}
}
/**
* #return the minutes parked
*/
public int getMinutesParked()
{
return minutesParked;
}
}
here is my ParkingMeter class:
/**
* This is a ParkingMeter class for Impark.
*
* #author Tre
* #version 2.0 15 October 2015
*/
public class ParkingMeter
{
private int minutesPaid;
private String methodPaid;
/**
* #param newMinutesPaid the minutes paid for parking meter
*/
public ParkingMeter()
{
}
/**
* #return the minutes paid
*/
public int getMinutesPaid()
{
return minutesPaid;
}
/**
* #return the method paid
*/
public String getMethodPaid()
{
return methodPaid;
}
/**
* #param paidBy the payment method customer will paid by
*/
public void setMethodPaid(String paidBy) /* BONUS for creating method paid */
{
if(methodPaid=="Visa"){
methodPaid = paidBy;
}
else if(methodPaid=="Master Card"){
methodPaid = paidBy;
}
else if(methodPaid=="American Express"){
methodPaid = paidBy;
}
else if(methodPaid=="Cash"){
methodPaid = paidBy;
}
else if(methodPaid=="Debit"){
methodPaid = paidBy;
}
else{
methodPaid = paidBy;
}
}
/**
* #param quantity the added minutes paid must not have a negative number
*/
public void addMinutesPaid(int quantity)
{
if(quantity>=0){
minutesPaid+=quantity;
}
}
}
and here is my ParkingTicket class:
/**
* This is a ParkingTicket class for Impark.
*
* #author Tre
* #version 1.0
*/
public class ParkingTicket
{
private final String referenceNumber;
private static String carLicensePlate;
private static int carMinutesParked;
private static int meterMinutesPaid;
private static int count = 1000;
private static String PREFIX = "V";
/**
* #param recorededLicense the value of the tick number
*/
private ParkingTicket(String recordedLicense, int newCarMinutesParked, int newMeterPaidMinutes)
{
referenceNumber = (PREFIX+count++);
carMinutesParked = newCarMinutesParked;
meterMinutesPaid = newMeterPaidMinutes;
}
/**
* #param
*/
private ParkingTicket(Car parker, ParkingMeter parkee)
{
this(parker.getLicensePlate(), parker.getMinutesParked(), parkee.getMinutesPaid());
}
/**
* #return referenceNumber the reference number
*/
public String getReferenceNumber()
{
return referenceNumber;
}
/**
* #return carLicensePlate the car's license plate
*/
public String getCarLicensePlate()
{
return carLicensePlate;
}
/**
* #return carMinutesParked the minutes car was parked
*/
public int getCarMinutesParked()
{
return carMinutesParked;
}
/**
* #return meterMinutesPaid the minutes paid on meter
*/
public int getMeterMinutesPaid()
{
return meterMinutesPaid;
}
/**
* #return count the with initial value of 1000
*/
public int getCount()
{
return count;
}
public static ParkingTicket checkParking(int carMinutesParked, int meterMinutesPaid)
{
Car parker = carMinutesParked;
ParkingMeter parkee = parkee;
if(carMinutesParked>meterMinutesPaid){
return new ParkingTicket(parker, parkee);
}
else if(carMinutesParked<=meterMinutesPaid){
return null;
}
return new ParkingTicket(parker, parkee);
}
}
This requirement:
Using a Car parameter and a ParkingMeter parameter, decide whether a
ParkingTicket object should be created.
suggests that you provide two parameters to the checkParking method, one is of the type Car and one of the ParkingMeter. So it should be like so:
public static ParkingTicket checkParking(Car car, ParkingMeter meter)
This code :
Car parker = carMinutesParked;
ParkingMeter parkee = parkee;
won't even compile
line 1: you're trying to assign int to object - that's called type mismatch.
line 2: variable parkee is not declared anywhere (except for the headline of the question).
You see, only the Car object holds the information about the parking duration, and you need the object for creating parking ticket. Same for the ParkingMeter
It should be vice versa - you get the values from the objects:
int carMinutesParked = car.getMinutesParked();
int meterMinutesPaid = meter.getMinutesPaid();
and proceed from here with if( or even use it in if without declaring temporary variables).
This one:
Invoke ParkingTicket(parker, parkee) if a ticket was merited, and
return the result.
you did OK.
Now this requirement:
Return null if a ticket was not merited.
suggest the method will return null, not string that equals to "null" .
So, based on these requirements it should rather be:
public static ParkingTicket checkParking(Car car, ParkingMeter meter)
{
//sanity check (bonus)
if ((car == null) || (meter == null))
return null;
if(car.getMinutesParked() > meter.getMinutesPaid()){
return new ParkingTicket(car, meter);
}
return null;
}
Note however, I don't know if you need any additional logic in this code and don't suggest this should be your final version, just explaining the general approach.

Java - Overriding A Parent Class

I am new to Java and I am working on a project that works with calculating prices with/without employee discounts. After reading the following code could someone explain to me how I would need to change my code in order to get the correct output? I will explain this question in more detail at the end of the post.
Parent Class (I am NOT allowed to edit this):
public class GroceryBill {
private Employee clerk;
private List<Item> receipt;
private double total;
private double internalDiscount;
public GroceryBill(Employee clerk) {
this.clerk = clerk;
receipt = new ArrayList<Item>();
total = 0.0;
internalDiscount = 0.0;
}
public void add(Item i) {
receipt.add(i);
total += i.getPrice();
internalDiscount += i.getDiscount();
}
public double getTotal() {
return Math.rint(total * 100) / 100.0;
}
public Employee getClerk() {
return clerk;
}
public void printReceipt() {
System.out.println(this);
}
private String valueToString(double value) {
value = Math.rint(value * 100) / 100.0;
String result = "" + Math.abs(value);
if(result.indexOf(".") == result.length() - 2) {
result += "0";
}
result = "$" + result;
return result;
}
public String receiptToString() {
String build = "items:\n";
for(int i = 0; i < receipt.size(); i++) {
build += " " + receipt.get(i);
if(i != receipt.size() - 1) {
build += "\n";
}
}
return build;
}
public String toString() {
return receiptToString() + "\ntotal: " + valueToString(total);
}
public String discountToString() {
return receiptToString() + "\nsub-total: " + valueToString(total) + "\ndiscount: " + valueToString(internalDiscount) + "\ntotal: " + valueToString(total - internalDiscount);
}
public static class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static class Item {
private String name;
private double price;
private double discount;
public Item(String name, double price, double discount) {
this.name = name;
this.price = price;
this.discount = discount;
}
public double getPrice() {
return price;
}
public double getDiscount() {
return discount;
}
private String valueToString(double value) {
String result = "" + Math.abs(value);
if(result.indexOf(".") == result.length() - 2) {
result += "0";
}
result = "$" + result;
return result;
}
public String toString() {
return name + " " + valueToString(price) + " (-" + valueToString(discount) + ")";
}
}
}
Here is my code:
public class DiscountBill extends GroceryBill
{
    private int myDiscountCount;
    private double myDiscountAmount;
    private double myPrice;
    
    public DiscountBill(Employee clerk, boolean preferred)
    {
        super(clerk);
        
        String name = "";
        double price = 0;
        double discount = 0;
        
        GroceryBill.Item myBill = new GroceryBill.Item(name, price, discount);
        myDiscountAmount = myBill.getDiscount();
        
        if (myDiscountAmount > 0 && preferred)
        {
            myDiscountCount++;
        }
    }
public void add(Item myBill)
{
myPrice += myBill.getPrice();
myDiscountAmount = myBill.getDiscount();
if (myDiscountAmount > 0 )
{
myDiscountCount++;
}
}
public double getTotal()
    {
if (myDiscountCount > 0)
{
return myPrice - myDiscountAmount;
}
        return myPrice;
    }
    public int getDiscountCount()
    {
        return myDiscountCount;
    }
    public double getDiscountAmount()
    {
        return myDiscountAmount;
    }
    public double getDiscountPercent()
    {
        return ((myPrice - myDiscountAmount) / myPrice * 100);
    }
}
Lastly, here is the expected output followed by my specific question:
The outputs that I am getting for my methods are one step ahead of where they should be. That is to say, my getTotal, for example, should start out as 1.35 (the first value input by the website I am using that tests my child class that I wrote) and then after another step it should be reduced to 1.1 (the website uses the employee discount using the boolean preferred from the constructor), but my program outputs 1.1 because my child class overrides the parent class's getTotal() method and never starts at the total it should (1.35). Basically I need to know how to get those original values from my parent class and THEN use the override methods to get the values after they are changed. If you want to see how this website operates, here is a link to the question I'm working on.
P.S. Please let me know if I need to give more/less information and ways that I can clean up this post or make it easier to understand. If my question was too broad, please ask me what you don't understand about it and I'll try my best to tell you! Thank you!
I'm not sure if that is what you want. Do you want to call parent method?
For that you can use super.parentMethodName
Please correct me if I'm wrong
As far as I understood your question, what you want to do is :
Add this additional code to your DiscountBill
public class DiscountBill extends GroceryBill
{
private static boolean isFirstTime = true;
public double getTotal()
{
if (!isFirstTime && myDiscountCount > 0)
{
return myPrice - myDiscountAmount;
}
isFirstTime = false;
return myPrice;
}
}

ArrayList is losing my reference

I have a static ArrayList (masterLog) that is in my main driver class. The ArrayList contains Event objects, the Event object has an ArrayList (heats) as a global variable. the heat object as an ArrayList (racers) as a global variable. Now when I have the following line of code:
System.out.println(ChronoTimer1009System.getMasterLog().get(0).getHeats().get(getCurHeat()).getRacers().toString());
this returns [] even though the getRacers() IS NOT empty!
When I call this:
System.out.println(getHeats().get(getCurHeat()).getRacers());
this returns the proper filled array.
I think I need to sync the masterLog ArrayList but I am unsure how. I have tried syncing it the way other threads on Stack Exchange have recommended but no luck.
it seems like the static ArrayList masterLog is updated two levels deep but not three levels deep if that makes sense.
What am I doing wrong?
UPDATE:
Maybe this will help explain:
In my main (driver) class, I have a static ArrayList called masterLog. The purpose of this ArrayLIst is to store instances of Event objects for later data retrieval. Now, without making it too complicated, the Event class contains an ArrayList called heats, and the Heat class contains an ArrayList called racers. When I access the masterLog ArrayList at some point in the program (when the other ArrayLists are populated with data), say for example by the call "masterLog.getHeats().get(0).getRacers()", the masterLog does not find any data in the racers ArrayList. It does, however, find data in the heats ArrayList. In other words, the object instance that is stored in the masterLog only updates information to a depth of 2 (not 3 if that makes sense).
UPDATE:
Here is some code:
ChronoTimer1009System class (driver)
package main;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
public class ChronoTimer1009System {
private Event curEvent;
private static Channel[] channels = new Channel[8];
private boolean state;
private static Stack<Log> log;
private static ArrayList<Event> masterLog;
private static Printer p;
public static Time globalTime;
private int oldLogSize; //used only in this.export()
public ChronoTimer1009System() throws UserErrorException{
for(int i=0; i<channels.length; ++i){channels[i] = new Channel(SensorType.NONE);} // initialize channels
masterLog = new ArrayList<Event>(); //this holds references to each event
this.newEvent(EventType.IND);
this.state = false; //system is initally off
log = new Stack<Log>();
p = new Printer();
globalTime = null;
oldLogSize = 0;
}
public void newEvent(EventType e) throws UserErrorException {
switch(e){
case IND: this.curEvent = new IND();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case PARIND: this.curEvent = new PARIND();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case GRP: this.curEvent = new GRP();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case PARGRP: this.curEvent = new PARGRP();ChronoTimer1009System.masterLog.add(this.curEvent);break;
}
for(Channel x : channels){if(x.getState()) x.toggleState();}
}
public void on() throws UserErrorException{
if(state) throw new IllegalStateException();
this.curEvent = new IND();
ChronoTimer1009System.globalTime = new Time(0);
state = true;
}
public void reset() throws UserErrorException{
if(state) state = false;
on();
}
public void exit(){
this.curEvent = null;
ChronoTimer1009System.globalTime = null;
if(!state) throw new IllegalStateException();
state = false;
}
public static Time searchElapsedByID(int idNum){
Time toReturn = null;
for(Log item : log){
if(item.getCompetitorNumber() == idNum){
toReturn = item.getElapsedTime(); break;
}
}
return toReturn;
}
/**
* #return the curEvent
*/
public Event getCurEvent() {
return curEvent;
}
/**
* #return the state
*/
public boolean isState() {
return state;
}
public static Channel getChan(int chan){
if(chan < 1 || chan > 8) throw new IllegalArgumentException("Argument is not in range");
return channels[chan-1];
}
public static void export(){
//*****FORMAT JSON*****
//before formating, a sort of the runners within each heat is needed to determine place.
String toJson = "{\"events\":[";
System.out.println(ChronoTimer1009System.getMasterLog().get(0).getHeats().get(0).getRacers().size());
//iterate through each event
for(int i = 0; i < ChronoTimer1009System.getMasterLog().size(); ++i){
//iterate through each heat of each event
toJson += "{\"name\":\"" + ChronoTimer1009System.getMasterLog().get(i).getType().toString() + "\",\"heats\":[";
for(int j = 0; j < ChronoTimer1009System.getMasterLog().get(i).getHeats().size(); ++j){
//iterate through each competitor in each heat
toJson += "{\"runners\":[";
System.out.println(ChronoTimer1009System.getMasterLog().get(i).getHeats().size());
ArrayList<Competitor> x = sortByPlace(ChronoTimer1009System.getMasterLog().get(i).getHeats().get(j).getRacers()); <----- on this line, the getRacers() part has a size of zero when it isn't empty.
for(int k = 0; k < x.size(); ++k){
//notice we are working with a sorted copy
//TODO make Competitor endTime the elapsed time
toJson += "{\"place\":\"" + String.valueOf(k+1) + "\",\"compNum\":\"" + x.get(k).getIdNum() + "\", \"elapsed\":\"" + x.get(k).getEndTime().toString() + "\"},";
}
toJson += "]},";
}
toJson += "]},";
}
toJson += "}";
System.out.println(toJson);
/*try{
URL site = new URL("http://7-dot-eastern-cosmos-92417.appspot.com/chronoserver");
HttpURLConnection conn = (HttpURLConnection) site.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
String data = "data=" + toJson;
out.writeBytes(data);
out.flush();
out.close();
System.out.println("Done sent to server");
new InputStreamReader(conn.getInputStream());
}
catch (Exception e)
{
e.printStackTrace();
}*/
}
private static ArrayList<Competitor> sortByPlace(ArrayList<Competitor> unsorted)
{
ArrayList<Competitor> whole = (ArrayList<Competitor>) unsorted.clone();
ArrayList<Competitor> left = new ArrayList<Competitor>();
ArrayList<Competitor> right = new ArrayList<Competitor>();
int center;
if(whole.size()==1)
return whole;
else
{
center = whole.size()/2;
// copy the left half of whole into the left.
for(int i=0; i<center; i++)
{
left.add(whole.get(i));
}
//copy the right half of whole into the new arraylist.
for(int i=center; i<whole.size(); i++)
{
right.add(whole.get(i));
}
// Sort the left and right halves of the arraylist.
left = sortByPlace(left);
right = sortByPlace(right);
// Merge the results back together.
merge(left,right,whole);
}
return whole;
}
private static void merge(ArrayList<Competitor> left, ArrayList<Competitor> right, ArrayList<Competitor> whole) {
int leftIndex = 0;
int rightIndex = 0;
int wholeIndex = 0;
// As long as neither the left nor the right arraylist has
// been used up, keep taking the smaller of left.get(leftIndex)
// or right.get(rightIndex) and adding it at both.get(bothIndex).
while (leftIndex < left.size() && rightIndex < right.size())
{
if ((left.get(leftIndex).getEndTime().compareTo(right.get(rightIndex)))<0)
{
whole.set(wholeIndex,left.get(leftIndex));
leftIndex++;
}
else
{
whole.set(wholeIndex, right.get(rightIndex));
rightIndex++;
}
wholeIndex++;
}
ArrayList<Competitor>rest;
int restIndex;
if (leftIndex >= left.size()) {
// The left arraylist has been use up...
rest = right;
restIndex = rightIndex;
}
else {
// The right arraylist has been used up...
rest = left;
restIndex = leftIndex;
}
// Copy the rest of whichever arraylist (left or right) was
// not used up.
for (int i=restIndex; i<rest.size(); i++) {
whole.set(wholeIndex, rest.get(i));
wholeIndex++;
}
}
/**
* #return the log
*/
public static Stack<Log> getLog() {
return log;
}
/**
* #return the masterLog
*/
public static ArrayList<Event> getMasterLog() {
return masterLog;
}
/**
* #return the p
*/
public static Printer getPrinter() {
return p;
}
}
Event Class:
package main;
import java.util.ArrayList;
public abstract class Event extends Display{
private ArrayList<Heat> heats;
private int curHeat; //private means only this class can modify, not the subclasses
private Competitor curComp;
private String name;
public Event(String name) throws UserErrorException{
this.name = name;
heats = new ArrayList<Heat>();
curHeat = -1;
curComp = null;
createRun();
}
/**
* This method will be used by all EventTypes and will not change
* regardless of the EventType.
* #throws UserErrorException
*/
public void createRun() throws UserErrorException{
heats.add(new Heat()); ++curHeat;
}
/**
* #return the heats
*/
public ArrayList<Heat> getHeats() {
return heats;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #return the currentHeat
*/
public int getCurHeat() {
return curHeat;
}
/**
* #return the curComp
*/
public Competitor getCurComp() {
return curComp;
}
/**
* #param curComp the curComp to set
*/
public void setCurComp(Competitor curComp) {
this.curComp = curComp;
}
/* (non-Javadoc)
* #see Display#displayHeatNumber()
*/
#Override
public String displayHeatNumber() {
// TODO Auto-generated method stub
return "Heat: " + (curHeat+1);
}
/* (non-Javadoc)
* #see Display#displayFinished()
*/
#Override
public String displayFinished() {
String toReturn = "";
boolean noRunners = true;
for(Competitor x : getHeats().get(getCurHeat()).getRacers()){
if(x.getEndTime() != null){
toReturn += "\n" + x.getIdNum() + " " + (ChronoTimer1009System.searchElapsedByID(x.getIdNum()).equals(new Time(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE)) ? "DNF" : ChronoTimer1009System.searchElapsedByID(x.getIdNum()).toString() + " F");
noRunners = false;
}
}
if(noRunners){toReturn = "no runners have finished";}
return toReturn;
}
public abstract void endRun() throws UserErrorException;
public abstract void trigChan(int chan, boolean dnf) throws UserErrorException;
public abstract void cancel(int ln) throws UserErrorException;
public abstract EventType getType();
}
Heat class:
package main;
import java.util.ArrayList;
public class Heat {
private ArrayList<Competitor> racers;
//private ArrayList<Competitor> racers;
private int currentCompetitor;
/**
* Constructor
*/
public Heat(){
racers = new ArrayList<Competitor>();
//racers = new ArrayList<Competitor>();
currentCompetitor = 0;
}
/**
* Set selected racer as next on to start
* #param racer the racer to start next
*/
public void setNextCompetitor(Competitor x){
int pos = racers.indexOf(x);
if(pos == -1 || pos<currentCompetitor) throw new IllegalArgumentException("Competitor not in the race! Please add first");
for(int i = pos; i>currentCompetitor; --i){
racers.set(i, racers.get(i-1));
}
racers.set(currentCompetitor, x);
}
/**
* Take the selected runner (the next runner) out from the race
* #param racer the runner to be cleared
*/
public void clearNextCompetitor() throws UserErrorException {
if(racers.size()-(currentCompetitor)<1) throw new UserErrorException("No runners to clear!");
for(int i = currentCompetitor+1; i<racers.size(); ++i){
racers.set(i-1, racers.get(i));
}
racers.remove(racers.size()-1);
}
/**
* basically a remove method
* #param x
*/
public void remove(Competitor x){
int pos = racers.indexOf(x);
if(pos < 0) throw new IllegalArgumentException("runner does not exists");
racers.remove(pos);
}
/**
* Swaps two runners positions in line
*/
public void swap() throws UserErrorException{
int count = 0;
for(Competitor x : racers){
if(x.getStartTime() == null) ++count;
}
if(count > 1 && currentCompetitor + 1 <= racers.size()){
Competitor first = racers.get(currentCompetitor);
Competitor second = racers.get(currentCompetitor+1);
racers.set(currentCompetitor, second);
racers.set(currentCompetitor+1, first);
}
else{
throw new UserErrorException("Not enough competitors to swap");
}
}
/**
* Add a competitor to the end of the current line of competitors if any
* #param x the competitor to add
*/
public boolean addCompetitor(Competitor x) throws UserErrorException{
if(x.getIdNum() < 0 || x.getIdNum() > 99999) throw new UserErrorException("ID number out of range");
if(x.getRunNum() < 0) throw new IllegalArgumentException("Run Num Out of range");
boolean add = true;
for(Competitor i : racers){
if(i.getIdNum() == x.getIdNum()){
add = false;
break;
}
}
if(add){
racers.add(x);
}
return add;
}
/**
* Retrieve the next competitor if there is one
* #return the next competitor
*/
public Competitor getNextCompetitor() throws UserErrorException{
if(!hasNextCompetitor()) throw new UserErrorException("There are no more competitors!");
while(racers.get(currentCompetitor).isCompeting()){++currentCompetitor;}
return racers.get(currentCompetitor++);
}
/**
* used to fix the order of the queue after cancel is called
*/
public void fix(EventType x){
switch(x){
case IND:
--currentCompetitor;
break;
case GRP: case PARGRP: case PARIND:
for(int i = 0; i<racers.size(); ++i){
if(racers.get(i).getStartTime() == null){
currentCompetitor = i;
break;
}
}
break;
}
}
/**
* Is there another competitor to go?
* #return whether or not there is another competitor to go.
*/
public boolean hasNextCompetitor(){
return currentCompetitor < racers.size();
}
/**
* Return a 1D array view of the competitors
* #return
*/
public ArrayList<Competitor> getRacers(){
return racers;
}
}
in the export method of the ChronoTimer1009System class, I point out where the error is and what is happening

Check with what object the method is triggered

I call this method in java:
private void updateDisplay()
{
displayString = hours.getDisplayValue() + ":" +
minutes.getDisplayValue();
}
What triggers this method two times for hours and minutes:
public String getDisplayValue()
{
if(value < 10) {
return "0" + value;
}
else {
return "" + value;
}
}
My question is how can i check in getDisplayValue if the method is triggerd as minute or as hour? For example:
public String getDisplayValue()
{ if(this == minutes){
if(value < 10) {
return "0" + value;
}
else {
return "" + value;
}
}
Entire code:
public class ClockDisplay
{
private NumberDisplay hours;
private NumberDisplay minutes;
private String displayString; // simulates the actual display
/**
* Constructor for ClockDisplay objects. This constructor
* creates a new clock set at 00:00.
*/
public ClockDisplay()
{
hours = new NumberDisplay(24);
minutes = new NumberDisplay(60);
updateDisplay();
}
/**
* Constructor for ClockDisplay objects. This constructor
* creates a new clock set at the time specified by the
* parameters.
*/
public ClockDisplay(int hour, int minute)
{
hours = new NumberDisplay(24);
minutes = new NumberDisplay(60);
setTime(hour, minute);
}
/**
* This method should get called once every minute - it makes
* the clock display go one minute forward.
*/
public void timeTick()
{
minutes.increment();
if(minutes.getValue() == 0) { // it just rolled over!
hours.increment();
}
updateDisplay();
}
/**
* Set the time of the display to the specified hour and
* minute.
*/
public void setTime(int hour, int minute)
{
hours.setValue(hour);
minutes.setValue(minute);
updateDisplay();
}
/**
* Return the current time of this display in the format HH:MM.
*/
public String getTime()
{
return displayString;
}
/**
* Update the internal string that represents the display.
*/
private void updateDisplay()
{
displayString = hours.getDisplayValue() + ":" +
minutes.getDisplayValue();
}
}
And:
public class NumberDisplay
{
private int limit;
private int value;
/**
* Constructor for objects of class NumberDisplay.
* Set the limit at which the display rolls over.
*/
public NumberDisplay(int rollOverLimit)
{
limit = rollOverLimit;
value = 0;
}
/**
* Return the current value.
*/
public int getValue()
{
return value;
}
/**
* Return the display value (that is, the current value as a two-digit
* String. If the value is less than ten, it will be padded with a leading
* zero).
*/
public String getDisplayValue()
{
if(value < 10) {
return "0" + value;
}
else {
return "" + value;
}
}
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public void setValue(int replacementValue)
{
if((replacementValue >= 0) && (replacementValue < limit)) {
value = replacementValue;
}
}
/**
* Increment the display value by one, rolling over to zero if the
* limit is reached.
*/
public void increment()
{
value = (value + 1) % limit;
}
}
}
Do it using reflection by checking the stack trace, see Thread#getStackTrace:
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
Go through the API and see what methods are useful for your needs.
But why don't you simply pass an identifier that allows you to detect who called the method?
pass a parameter into getDisplayValue() function like this
getDisplayValue(char c)
and change your function definition to :
public String getDisplayValue(char c)
{
if(c == 'h'){
if(value < 10) {
return "0" + value;
}
else {
return "" + value;
}
}
else if(c=='m'){
return value*60;
}
}
and change updateDisplay() to :
private void updateDisplay()
{
displayString = hours.getDisplayValue(h) + ":" +
minutes.getDisplayValue(m);
}
Introduce a boolean parameter in the function declaration
public String getDisplayValue(Boolean isMinute)
{
if(isMinute)
{
if(value < 10) {
return "0" + value;
}
else {
return "" + value;
}
}
else{
// not a minute, continue
}
}
you can call this like
displayString = hours.getDisplayValue(false) + ":" +
minutes.getDisplayValue(true);
i will added a boolean flag in ClockDisplay i.e. isHour. And will change the constructure:
class ClockDisplay{
boolean isHour;
public ClockDisplay(boolean isHour)
{
hours = new NumberDisplay(24);
minutes = new NumberDisplay(60);
updateDisplay();
this.isHour=isHour;
}
...........
...........
}
Now in NumberDisplay i will change the method:
public String getDisplayValue(ClockDisplay c)
{
if(value < 10) {
return "0" + value;
}
else {
return "" + value;
}
c.
}
Now inside the method getDisplayValue() you can call any method on top of c, and it can print accordingly because you have set isHour accordingly.
The reason behind my design is: The abstraction whether hour or minute it should be encapsulated inside ClockDisplay. So just pass the ClockDisplay reference to getDisplayValue().
You can introduce 2 sub-classes
public class HourDisplay extends NumberDisplay {
// override getDisplayValue method the way you want
}
public class MinuteDisplay extends NumberDisplay {
// override getDisplayValue method the way you want
}
Then in ClockDisplay constructor
public ClockDisplay()
{
hours = new HourDisplay(24);
minutes = new MinuteDisplay(60);
updateDisplay();
}

Categories

Resources