jcoffey
jcoffey

Reputation: 475

How to enforce an integer limit in an argument hint in Java

I'm new to Java after working for a few years in PHP and I'm trying to get an idea of some of the best practices and norms when working with Java.

I'm wondering if it makes sense to make a whole class to act as a custom type just to enforce a limit on the range of an integer argument?

For example:

class Person() {
  private int age;

  public Person(int age) {
    if(age < 0) {
      throw new IllegalArgumentException();
    }
    this.age = age;
  }

  public int getAge() {
    return age;
  }
}

Or:

class Person() {
  private Age age;

  public Person(Age age) {
    this.age = age;
  }

  public int getAge() {
    return age.toInt();
  }
}


class Age() {
  private int age;

  public Age(int age) {
    if(age < 0) {
      throw new IllegalArgumentException();
    }
    this.age = age;
  }  

  public toInt() {
    return age;
  }
}      

Also, in the second example I'm converting the Age object to an int in Person.getAge(), which is convenient but somehow feels wrong since Person's constructor takes an Age object. Any thoughts?

Thanks!

Upvotes: 1

Views: 604

Answers (6)

Matt
Matt

Reputation: 1119

The first one would get my vote too.

I'm not sure if it is the example here or not, but I wouldn't think setting a age out of range would be a programing error. Throwing IllegalArgumentException makes more sense when a programming error has occurred. Null or a negative age might make my list of conditions to throw an exception.

Based on the post's title, it might be good to consider if the same should be done for an upper limit. I would argue that (using the age example), depending on what is setting the age, that an upper limit might be better enforced by an object validator. The validation should be applied at some point when feedback to the object user can be captured for a reaction (e.g. before persistence) as this wouldn't necessarily be a programming error, but a situation that the user should address first or be notified of.

Upvotes: 0

duffymo
duffymo

Reputation: 309008

I think it's about enforcing limits, encapsulating behavior, etc. That's what object-oriented languages are all about. It's getting used to thinking about the world less in terms of primitives like doubles, ints, and strings and more in terms of objects that represent better abstractions that encapsulate and hide details from clients.

I would go for the first example as well. I'd also recommend NOT having an "age" data member, since it changes every year. Better to have a birthDate and calculate current age from it.

Upvotes: 4

TofuBeer
TofuBeer

Reputation: 61536

I prefer the second version with the Age class as it lets you more easily test the "age" functionality without needing a Peron instance. Also you are able to use the Age in something else, such as a Warrenty.

Having an int for the Age is not a great idea generally - since things gain more age over time. A "creation date" is more general purpose (inside the Age class, just use a Date instead of the int).

Also, you will save yourself a lot of time if you do "throw new IllegalArgumentException("age cannot be < 0, was: " + age);" so that you can know what the offending value was (makes it easier to track bad data down when you know what the value is).

Upvotes: 1

Zeograd
Zeograd

Reputation: 1481

I would also use the first version unless your Age notion is wide spread in your project, in which case you should go the 2nd way around and also be consistent and return an Age object in getAge. Age should have an easy accessor to get the encapsuled int.

Upvotes: 1

JaakkoK
JaakkoK

Reputation: 8397

I think your second example is a bit overkill for this case, as you only have a single integer with a single constraint on it, and Age does not have any behavior associated with it. If any of these were different, for instance, if you had more data with interrelated constraints, it might make sense to separate those into their own class. So your second design isn't really wrong, just unsuitable for this toy example.

For your second example, I would probably have the Person.getAge method return an Age object instead of an int. Again, with this toy example it's harder to see a difference, but returning an int feels like a bit too much coupling between Person and Age.

Upvotes: 4

Dmitry
Dmitry

Reputation: 2993

I think first example is ok. Also you should describe thrown exception in javadoc, so user of your class would know about this behavior feature.

Upvotes: 1

Related Questions