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

Fahri Can
Fahri Can
9,921 Points

How can I verify that only letters or the $ character are used

Is there any other way instead of using regular expressions?

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;
  }

  public void applyDiscountCode(String discountCode) {
    this.discountCode = normalizeDiscountCode(discountCode);
  }

  private String normalizeDiscountCode(String discountCode){

    if(!discountCode.matches("[a-zA-Z]($)")){
      throw new IllegalArgumentException("Invalid discount code");
    }
    return discountCode.toUpperCase();
  }
}
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"
    }

  }
}

12 Answers

Seth Kroger
Seth Kroger
56,413 Points

matches() has to match an entire line/string, so you need to use + to match one or more, not just a single character . You also need to put the dollar sign inside the character class like this "[a-zA-Z$]+"

Fahri Can
Fahri Can
9,921 Points

Thank you very much Seth!

Simon Coates
Simon Coates
28,694 Points

In the event it's helpful to anyone in the future, mine was:

  private String normalizeDiscountCode(String discountCode){
    for(char letter: discountCode.toCharArray()){
        if(!Character.isLetter(letter) && letter != 36){
         throw new IllegalArgumentException("Invalid discount code.");
        }
    }       
    return discountCode.toUpperCase();      
  }

It only differs from earlier answers in that i used the enhanced for loop, and tried to use the ascii integer code for $. (for whatever reason, i drew a mental blank on representing characters and went straight to ascii. Using '$' is probably a better option, and clearer)

One year from now and you will be asking what "36" means, or anyone else reading that code. Google "magic numbers".

Simon Coates
Simon Coates
28,694 Points

I mentioned that '$' was clearer. I added my code sample because the for each loop seemed more robust than more manual handling, and didn't feel inclined to correct my code and pretend that I hadn't made a mistake. If nothing else, it gives people an opportunity to see something slightly different that they might see in the wild and (in this case) appreciate why it's a bad idea. I didn't know the 'magic numbers' nomenclature. It should help me remember. thanks. (if you feel inclined to answer, what are the circumstances in which it's useful to know characters are secretly numbers?)

Arash Abedin
Arash Abedin
12,107 Points

This one worked for me: private String normalizeDiscountCode(String discountCode){

for (int i = 0; i < discountCode.length; i++) {

char x = discountCode.charAt(i);

if ((!Character.isLetter(x)) && (x!='$')){

throw new IllegalArgumentException("Invalid discount code");

}

discountCode.length; change to discountCode.length();

If you don't want to use regex, you can loop through all characters in a String and check if it is a letter with the static method Character.isLetter() or if it's equal to $.

Benjamin Orimoloye
Benjamin Orimoloye
23,328 Points

you can change String discountCode toCharArray() and then check if (Character.isLetter() or equal to "$" using the for each loop

Taebin You
Taebin You
4,786 Points

private String normalizeDiscountCode(String discountCode){

for (int i = 0; i < discountCode.length(); i++){
  char [] ndc = discountCode.toCharArray();
  if (! Character.isLetter(ndc[i]) && ndc[i] != '$'){
   throw new IllegalArgumentException("Invalid discount code"); 
  }

}
return discountCode.toUpperCase();

Looks messy, but this worked

Simon Coates
Simon Coates
28,694 Points

your code creates a lot of redundant character array objects. As you observed, it should work, but the line

char [] ndc = discountCode.toCharArray();

should ideally be outside the loop. (this may be obvious to you, but i though i'd mention it for future users)

lap Nguyen
lap Nguyen
715 Points

Taebin, your code works and helped me complete the task... to be honest it was a bit confusing and a bit advanced, with the 'ndc' and 'int i = o; 1' first me at first but once I took a closer look it made sense to me. thanks.

Sean M
Sean M
7,344 Points

QUESTION: Can somebody explain the use of this part? I understand the rest, just not this section. Thank you.

 for (char letter: discountCode.toCharArray()) {
Simon Coates
Simon Coates
28,694 Points

toCharArray is called on the string, which returns an array of chars (ie char[]). The for loop takes a collection following the : (which should be read as 'in'). Each iteration of the loop, a different value from the collection is loaded into the loop variable (here this is called 'letter' and is type char), allowing you to access it within the loop body ( usually within a set of {}). You read it as "for each value in the collection, do the following".

Sean M
Sean M
7,344 Points

Okay, that makes more sense. Thanks Simon.

Kourosh Raeen
Kourosh Raeen
23,733 Points

If you want to fix the regex try "[a-zA-Z\$]+". Otherwise, Pedro's answer looks good.

Could you explain me where did "Character" come from?

In this statement from Simon: if(!Character.isLetter(letter)

Simon Coates
Simon Coates
28,694 Points

see https://docs.oracle.com/javase/7/docs/api/java/lang/Character.html . Java has a bunch of wrapper classes for the primitive types (int, char, bool). These classes include static methods related to the particular type. In this example, this is a helper method on the character class to help you determine in your char is a letter.

Thank you Simon

Richard Min
PLUS
Richard Min
Courses Plus Student 4,117 Points

Here is my long newb version which still works. Simon Coates' version is much better:

  private String normalizeDiscountCode(String discountCode) {
    for (char letter : discountCode.toCharArray()) {

      if (Character.isLetter(letter)) {
        System.out.println("Code is a letter. Valid code.");      //this line of code is unnecessary. I just wrote it to make it clear.
      } else if(letter == '$') {
        System.out.println("Code is a dollar sign. Valid code.");   //this line of code is unnecessary.
      } else {
        throw new IllegalArgumentException("Invalid discount code");
      }

    }
    return discountCode.toUpperCase();
  }