tags:

views:

124

answers:

3

Hey, This is just a simple exercise from class that I decided to have a go at putting an exception in. According to the book input for this problem is supposed to be in the following format: APRIL 19, 2009 What I'm trying to do with my exception is make sure the user(whoever grades it) follows those parameters so my program works. Does this look ok? Could I have done anything better?

Edit: Thanks for the timely answers! I know I have a lot to learn but hopefully one day I'll be capable enough to answer questions on here. cheers

import jpb.*;

public class ConvertDate {
    public static void main(String[] args) {
        try{
        SimpleIO.prompt("Enter date to be converted: ");
        String bam = SimpleIO.readLine();
        bam = bam.trim().toLowerCase();
        //empty space is taken off both ends and the entirety is put in lower case
        int index1 = bam.indexOf(" ");
        int index2 = bam.lastIndexOf(" ");
        int index3 = bam.indexOf(",");
        /*critical points in the original string are located using indexing to divide and conquer
        in the next step*/
        String month = bam.substring(0,index1);
        String up = month.substring(0, 1).toUpperCase();
        String rest = month.substring(1,index1);
        String day = bam.substring(index1, index3).trim();
        String year = bam.substring(index2+1);
        //now all the pieces are labeled and in their correct cases
        System.out.println("Converted date: " +day +" " +up +rest +" " +year);
        //everything comes together so perfectly
        } catch(StringIndexOutOfBoundsException e){
            System.out.println("best type that in like the book does on page 125...");}
        }
}
+6  A: 

Here are a few thoughts. These are just my opinion, so take them with a grain of salt or ignore completely if you wish:

  1. I don't know what that import statement is doing, but it's possible to do all this without introducing the dependency on the library. You should be aware of the effect that dependencies have.
  2. I hate the kind of comments that you've added. I know that students and professors love them, but as a professional I find that they're less informative than the code itself and only add clutter.
  3. I would not put all this logic into a main method. I'd encapsulate it into a class or static method so I could reuse it. It's a useless student exercise as written.
  4. You tested the "blue sky" happy path, where everything works. I'd recommend looking at something like JUnit and start thinking about edge and exception cases. Try more inputs that test to break your method. It'll improve that way. Your current method guarantees that your code will bonk with other cases that are easy to think of (e.g., passing in a string that isn't month-day-year).

Here's how I might write the same thing:

import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;

public class ConvertDate 
{
    private static final DateFormat DEFAULT_FORMAT;

    static
    {
        DEFAULT_FORMAT = new SimpleDateFormat("MM-dd-yyyy");
        DEFAULT_FORMAT.setLenient(false);
    }

    public static void main(String[] args) 
    {
        for (String dateString : args)
        {
            try
            {
                Date date = DEFAULT_FORMAT.parse(dateString);
                System.out.println(date);
            }
            catch (ParseException e)
            {
                System.out.println("invalid date string: " + dateString);
            }
        }
    }
}
duffymo
_I hate the kind of comments_ indeed. @user463372, write comments that tell **why** you are doing something, not **what** you're doing. We can read the code, we know what you're doing. But a little insight into why you are doing it can shed tons of light.
Tony Ennis
Beware, the Java date formatting classes are annoying IMO. duffymo's program, which looks very reasonable, accepts 13-32-2010 as a valid date. `parse()` is a tad loose...
Tony Ennis
@Tony Ennis - Try that date now. Not loose anymore.
duffymo
I never understood why Lenient(false) isn't the default...
Tim Büthe
@Tim - agreed. Even smart people can stand to have their code tightened up.
duffymo
OMG. Is there a `Lenient()` ????
Tony Ennis
Holy cow, I just ran the code and it rejects my bogus dates. How many times have I coded crud to prevent the looseness! I didn't know!
Tony Ennis
@Tim - I think a new subclass of DateFormat might start making an appearance in my code ;-) Yeah, three comments in a row. I can't help it - I'm giddy.
Tony Ennis
@Tony Ennis - I wouldn't do that.
duffymo
@duffymo why not?
Tony Ennis
@Tony - as your teammate, I would be far more likely to just use DateFormat and learn how to setLenient properly. One less dependency for me. I'm not a fan of subclassing. I think it's overrated, especially for situations like this. Learn how to use the library class properly.
duffymo
+5  A: 

Generally using exceptions for things that are a part of the logic of your program is frowned upon. Your logic should be:

   if(The Input is well formed){
       parse the date
   }else{
       Tell the user that the input is wrong
   }

But your program is:

    try{
         parse the date

     }catch(){
         tell the user the input is wrong
     }

To determine if the input is well formed you can test it for length, get the month substring as you are doing and test that for length, get the day substring and test if it is an integer etc etc.

A program should never throw a StringIndexOutOfBoundsException because this is something that you can check before you use the substring method.

Vincent Ramdhanie
A: 

You should really use a combination of SimpleDateFormat and Regex Pattern to validate the input.

RegexPattern will make sure the right components are in right place: MONTH(space)2DIGITDAY(comma)(space)4DIGITYEAR

and SimpleDateFormat will make sure the date components are legal eg:APRIL is not spelled as ARPIL.

public static void main(String[] args) throws Exception{
    String dateStr = "ARPIL 19, 2009";

    String validPattern = "[A-Z]* [0-9]{2}, [0-9]{4}";
    boolean isValidPattern = Pattern.matches(validPattern,dateStr);  //make sure the input string is of the desired pattern

    if(isValidPattern){
        SimpleDateFormat sdf = new SimpleDateFormat("MMMMM dd, yyyy");
        Date date = sdf.parse(dateStr);
    }else{
        throw new IllegalArgumentException("Input string does not match the required pattern");
    }
}
Mihir Mathuria
That regex... not so good. Allows the month to be missing, requires leading zeros on day-of-month. That being said, exactly what good does it do, anyway?
Tony Ennis
Even though MMMMM is specified as the month format to SimpleDateFormat it validates APR (instead of say, APRIL as required by the user). So the regexpattern should help eliminate those kind of inputs. You are right about the month to be missing, should check for atleast 3 chars (MAY being the shortest). Will edit that in a while. Thanks for the shoutout
Mihir Mathuria
What service does the regexp provide that the SimpleDateFormat does not?
Tony Ennis
I'm totally with Tony. Why do you want to double check?
Tim Büthe
So, I was trying to make the program guard against user mistakes like inputting "09" instead of "2009" for the year. The SimpleDateFormat would validate both, but both the Date objects would be significantly different. Not sure if we can avoid these kind of mistakes using SimpleDateFormat only.
Mihir Mathuria