noobdev
noobdev

Reputation: 21

Java try catch in constructor

I wrote this class that returns the fiscal year:

public class Fiscal {

private Calendar calendar;

public FiscalDate(String date) {
    try {
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date formattedDate = formatter.parse(date);
        this.calendarDate = Calendar.getInstance();
        this.calendarDate.setTime(formattedDate);
    }
    catch (ParseException e) {
        System.out.print(e);
    }
}
}

I'm using it like the following:

String test = new Fiscal("2020-03-31").display();

Everything works fine, I'm just wondering if there is anything wrong with my try and catch in the constructor? Any ways I can improve this class?

Upvotes: 0

Views: 902

Answers (3)

leo277
leo277

Reputation: 439

I would argue against any code in the constructor. You could follow the guidelines in this article: https://www.yegor256.com/2015/05/07/ctors-must-be-code-free.html

Basically initializing your object with the string representation and parsing only at #displayFiscalYear. Any additional behavior can be achieved through decorators, like caching to avoid repeated computes.

It might seem over complicated, but IMHO it's the best approach. If this doesn't convince you though, I would go with a factory approach. Compute the parsing in a factory method and the constructor is directly initialized with a Calendar object.

P.S. I would also recommend to move to java 8's java.time if you can.

Upvotes: 2

Anonymous
Anonymous

Reputation: 86399

  1. Use LocalDate from java.time, the modern Java date and time API, for a date.
  2. Catching an exception in the constructor is generally bad. You may do it if you can still initialize the object to a fully valid and meaningful state or you want to wrap the exception into a different exception that you throw to the caller.

java.time

public class FiscalDate {

    private LocalDate calendarDate;

}

A LocalDate is a date in the proleptic Gregorian calendar without time of day. A Calendar is a date and time of day with time zone, week numbering scheme and more, theoretically in any calendar system. The Calendar class is also poorly designed and long outdated. So I recommend LocalDate.

Constructors

Now which constructors do we want? I’d find it natural to have a constructor that accepts a LocalDate:

    public FiscalDate(LocalDate calendarDate) {
        this.calendarDate = calendarDate;
    }

If you foresee that the caller will sometimes have the date as a string rather than a LocalDate, providing a convenience constructor that accepts a string is nice:

    /** @throws DateTimeParseException if dateString is not a valid date string in format yyyy-MM-dd */
    public FiscalDate(String dateString) {
        this(LocalDate.parse(dateString));
    }

The this() call calls the constructor from before. It’s similar to a super() call, only instead of calling a constructor in the superclass it calls a constructor in the same class. LocalDate.parse() throws a DateTimeParseException if the string cannot be parsed into a valid date. It’s an unchecked exception, so we need not declare that the constructor may throw it, but it’s nice for the caller to know, so we put it in the Javadoc comment.

I believe that deciding what to do in case of an invalid string date should be the job of the caller, not this class. So throwing the exception is appropriate (as it is or wrapped in a more appropriate exception type). If you were to catch the exception in the constructor, you would need to initialize the object, and I can’t see how you would be able to do that in any meaningful way.

Link

Upvotes: 0

Jason
Jason

Reputation: 5244

Yeah so like @Johnny Mopp said in the comments you shouldn't catch the exception silently, instead throw the exception and let the person who is implementing that class choose how to handle it.

public FiscalDate(String date) throws ParseException {
    DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
    Date formattedDate = formatter.parse(date);
    calendarDate = Calendar.getInstance();
    calendarDate.setTime(formattedDate);
}
try {
    FiscalDate date = new FiscalDate("my date string");

    // some code that utilizes date
} catch (ParseException exception) {
    // darn, something went wrong, time to handle it!
}

Upvotes: 3

Related Questions