evilpenguin
evilpenguin

Reputation: 5478

Avoid nested try-catch blocks

I have the following bit of Java code:

SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy mm:HH");
Date date;
try {
     date = df.parse(userString);
 } catch (ParseException e) {
     date = df.parse("07/12/2016 01:00");
     LOGGER.error("Could not parse date, reverting to default");
 }

So, what I'm trying to do is to parse the user input as a date and, if that fails, to replace it with a default date.

However, the second df.parse() requires a try-catch of its own, even though that's a value I know for certain will work. It doesn't make any sense for the second parse not to work and if it indeed doesn't, I have nothing more to do, I might as well terminate the program because the world has ended. :)

Is there a way to avoid the need for a second try-catch block?

Upvotes: 1

Views: 5612

Answers (6)

slipperyseal
slipperyseal

Reputation: 2778

You say it doesn't make sense to have the second try-catch. this is half true. yes, you are saying it wont fail but Java doesn't know this.

You could pre-parse a single default date reference, store is as a class member, and return that (but you'd still need a try catch on that - and it's not immutable).

There is nothing wrong with trying to reduce the lines of code. There are several answers to this question which give you work arounds for no try-catch but I think these make the code less clear and more error prone over all. There are schools of thought such as to avoid state flags, avoid nullable values, don't reassign variables etc.

I would just use a nested try-catch in this case and move on with your life. It's a little but ugly, but safer and clearer than than other approaches.

So while this isn't an answer to your question, I'm posting this is an answer because I think answering the question makes your code worse overall. :)

This is how I would write the function for best readability, maintainability and safety...

public Date parseDate(String userString) {
    SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy mm:HH");
    try {
        return df.parse(userString);
    } catch (ParseException e) {
        LOGGER.error("Could not parse date '" + userString + "' reverting to default");
        try {
            return df.parse("07/12/2016 01:00");
        } catch (ParseException shouldntHappen) {
            throw new RuntimeException(shouldntHappen);
        }
    }
}

Upvotes: 4

VGR
VGR

Reputation: 44414

The correct way to create a specific date is with the existing date-time classes:

LocalDateTime local = LocalDateTime.of(2016, 7, 12, 1, 0);
ZonedDateTime zoned = ZonedDateTime.of(local, ZoneId.systemDefault());
date = Date.from(zoned.toInstant());

You can also use Calendar. If you’re using a version of Java older than Java 8, Calendar is the only way to do it:

Calendar calendar = Calendar.getInstance();
calendar.set(2016, Calendar.JULY, 12, 1, 0, 0);
date = calendar.getTime();

Caution: Calendar.JULY is not equal to 7. Use the month constants to avoid errors.

Upvotes: 0

Onur
Onur

Reputation: 5625

If your default date is predetermined, meaning if you don't have to parse it, you can just use

date = new Date(1468285200L * 1000); // unix time * 1000(milliseconds)

Otherwise just use SimpleDateFormat.parse(String text, ParsePosition pos) like this;

date = df.parse("07/12/2016 01:00", new ParsePosition(0));

Which does not throw any ParseException but returns the date or null based on whether parsing was successful.

Upvotes: 2

Vasu
Vasu

Reputation: 22462

You can avoid nested try as shown below by setting the default date in the finally block by checking for isError flag to true upon ParseException :

    SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy mm:HH");
    Date date1;
    Date date2;
    boolean isError = false;
    try {
         date1 = df.parse("07/12/2016 01:00");
         date2 = df.parse(userString);
     } catch (ParseException e) {
         isError= true;
         LOGGER.error("Could not parse date, reverting to default");
     } finally {
         if(isError) {
             date2 = date1;
         }
     }

Upvotes: 2

Akash
Akash

Reputation: 74

ParseException is checked exception. So you have to write it in try catch block or in method declaration just write throws PraseException. But then your calling method has to catch the exception. There is no other way to avoid checked exceptions

Upvotes: -1

Scary Wombat
Scary Wombat

Reputation: 44854

I would move this functionality to a method, which can then be re-used

public static void main (String [] args) 
{

    Date dt = setDate ("07/12/2016 x1:00");
    if (dt == null) {
        dt = setDate ("07/12/2016 01:00");
    }

    System.out.println(dt);
}

private static Date setDate(String in) {

    SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy mm:HH");
    Date date = null;
    try {
         date = df.parse(in);
     } catch (ParseException e) {
         System.out.println("Could not parse date, reverting to default");
     }      

    return date;
}

Upvotes: 2

Related Questions