Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Java Java Objects Delivering the MVP Applying a Discount Code

Zachary Martin
Zachary Martin
3,545 Points

Having trouble with part one of this exercise

Not sure what im doing wrong

Order.java
public class Order {
  private String itemName;
  private int priceInCents;
  private String discountCode;

  public Order(String itemName, int priceInCents) {
    this.itemName = itemName;
    this.priceInCents = priceInCents;
  }

  public String getItemName() {
    return itemName;
  }

  public int getPriceInCents() {
    return priceInCents;
  }



  public String getDiscountCode() {
    return discountCode;
  }
private String normalizeDiscountCode(String discountCode) {
this.discountCode = discountCode.toUpperCase(discountCode);
  return discountCode;
}

  public void applyDiscountCode(String discountCode) {
    this.discountCode = discountCode;
  }
}
Example.java
public class Example {

  public static void main(String[] args) {
    // This is here just for example use cases.

    Order order = new Order(
            "Yoda PEZ Dispenser",
            600);

    // These are valid.  They are letters and the $ character only
    order.applyDiscountCode("abc");
    order.getDiscountCode(); // ABC

    order.applyDiscountCode("$ale");
    order.getDiscountCode(); // $ALE


    try {
      // This will throw an exception because it contains numbers
      order.applyDiscountCode("ABC123");
    } catch (IllegalArgumentException iae) {
      System.out.println(iae.getMessage());  // Prints "Invalid discount code"
    }
    try {
      // This will throw as well, because it contains a symbol.
      order.applyDiscountCode("w@w");
    }catch (IllegalArgumentException iae) {
      System.out.println(iae.getMessage());  // Prints "Invalid discount code"
    }

  }
}

1 Answer

andren
andren
28,558 Points

There are three issues:

  1. The normalizeDiscountCode method is only supposed to return the uppercased discount code, it is not supposed to set this.discountCode directly like you are doing in your method.
  2. The toUpperCase method returns an uppercased version of the string it is called from, you don't need to pass it a string as an argument like you are doing.
  3. The normalizeDiscountCode method has to be called from the applyDiscountCode method in order to actually do anything. In your code you never call normalizeDiscountCode.

If you fix those three issues like this:

private String normalizeDiscountCode(String discountCode) {
  // Return uppercased `discountCode`
  return discountCode.toUpperCase(); 
}

public void applyDiscountCode(String discountCode) {
  // Call normalizeDiscountCode with discountCode as the argument
  this.discountCode = normalizeDiscountCode(discountCode);
}

Then your code will work.

Zachary Martin
Zachary Martin
3,545 Points

I see, im still trying to internalize little nuances here and there. Am I correct in assuming that we're able to modify the return statement. thats my whole mental takeaway because up to this point I didn't know you could call things on return statements I thought they were to be left alone as is

andren
andren
28,558 Points

The return statement returns whatever the value you specify evaluates to.

In cases where you simply put a variable it evaluates to the content of the variable, if you put in a conditional like 5 > 3 it evaluates to whatever Boolean that results in (true in this case), and when you call a method it evaluates to whatever that method returns.

This is not only true of the return statement but of Java in general. The same exact things holds true for variable assignments for example, so when you assign a method call to a variable (like is done in the applyDiscountCode method above) you don't actually assign the method itself, but the returned value of the method.

Java will always evaluate values before it does anything with them. And there are no limits to what type of value you can return or assign to a variable.

Zachary Martin
Zachary Martin
3,545 Points

Gotcha, it's all sinking in slowly. One more question however. I was looking at this and I confused myself a little. I understand that using the this keyword makes you refer to the local varible name inside the method vs the global class one. Since we aren't using it in the normalize method whats the point of having it in the parameter if we can just wait to use i in the apply discount when we call normalize there in the

this.discountCode = normalizeDiscountCode(discountCode); line

andren
andren
28,558 Points

I understand that using the this keyword makes you refer to the local varible name inside the method vs the global class one.

Actually it's the other way around, this is used to refer to the global class variable, not using it makes you reference the local variable or parameter of the method.

This is the case because Java will always look for a variable in the current scope (which is the method) before it starts looking outside the scope. The this keyword allows you to reference the object directly, so this.discountCode tells Java that you are specifically talking about the discountCode variable that belongs to the object.

I'm not entirely sure I understand your question, but if I understand it correctly then you are basically asking why the methods could not have been structured like this instead:

private String normalizeDiscountCode() {
  // Return uppercased `discountCode`
  return this.discountCode.toUpperCase(); 
}

public void applyDiscountCode(String discountCode) {
  // Call normalizeDiscountCode with discountCode as the argument
  this.discountCode = normalizeDiscountCode();
}

If that is the question then the answer is that it could have been structured like that, in the sense that it would still work perfectly fine. But it would not be as flexible since the normalizeDiscountCode method would now be locked into always working on the discountCode instance variable. If you in the future needed some other string normalized then being able to reuse the existing method is a lot more efficient than having to create a new method just for that purpose.

In general it's considered a good practice to make methods not rely too much on anything from their outside beyond what they need to operate and parameters. Since that makes them far more reusable, which is important because in a real-world program a single method can easily be dozens to hundreds of lines long, and having to repeat that in multiple places would be a violation of the DRY principle and quite inefficient.