10

I have a public constructor which takes a parameter (int age) to create an object. I want to check if the passed parameter is legal or not, for example age cannot be negative. If its illegal, then don't create an object/instance. If legal, no problem.

I can only think of one way to do this -

Make constructor private. Create a static method with parameter (int age) to do all the checking and return a null if you pass it an illegal value. If you pass it a legal value, then create an object and return its reference. Is there any other way of doing it ? Maybe from inside the constructor itself ?

EDIT : I thought of one problem with the above method. The factory method/object creator method can only be a static method for obvious reasons. What happens if the factory method has to access a member variable (to do some checking) to create an object ? Then, we will be forced to make that member variable static. This may not be okay in all cases.

Does it make sense ?

FirstName LastName
  • 639
  • 2
  • 8
  • 21
  • 3
    What you describe is a *factory method*. If you want to avoid exceptionhandling, you can do that. Most people would just throw an IllegalArgumentException in the constructor. But as I said, that depends on your architechture. Both ways have their pros and cons. – Fildor Jan 18 '13 at 08:01
  • @Fildor - where can i learn more about their pros and cons. I want to compare them and understand which one to use in a situation. – FirstName LastName Jan 18 '13 at 08:02
  • 1
    @FirstNameLastName I would prefer the factory approach generally as exception handling has a cost – vishal_aim Jan 18 '13 at 08:05
  • 2
    If you ask 10 developers about this exception vs. null-check, you may get 12 answers. Facts are: If you return a null, you only know that "something" must have gone wrong. With Exceptions you can react differently to different flaws. For example you could make your own Excpetionclasses for AgeTooHigh and AgeTooLow just for a silly example. Some people will argument with execution time, some with personal taste ... Maybe smarter people than me have a drop-dead-argument for/against one of them ... – Fildor Jan 18 '13 at 08:16
  • 1
    @vishal_aim - what is the cost ? Is it speed of execution, memory used, something else ? – FirstName LastName Jan 18 '13 at 08:19
  • @Fildor - i added info to my question to discuss one possible disadvantage of factory method. please see if it makes sense. – FirstName LastName Jan 18 '13 at 08:27
  • In what way has it to acces a member? You can still access the member in the private constructor that is called in the static factory method. No problem. – Fildor Jan 18 '13 at 08:27
  • 2
    @FirstNameLastName probably it may help: http://stackoverflow.com/questions/299068/how-slow-are-java-exceptions and this one: http://stackoverflow.com/questions/2184935/performance-cost-of-coding-exception-driven-development-in-java – vishal_aim Jan 18 '13 at 08:32
  • @Fildor - I will respond to that after some time. Just checking my code before i respond. – FirstName LastName Jan 18 '13 at 08:36
  • 2
    @FirstNameLastName As a rule of thumb I always think in terms of "Is this a case that is an error, will probably rarely happen and needs special treatment outside normal control flow?" Then I make it an exception. If it is a question of control flow ("If age < 18 return null, else return acces token") then I don't use exceptions. – Fildor Jan 18 '13 at 09:40

4 Answers4

9

Is there any other way of doing it ? Maybe from inside the constructor itself ?

Yes. I suggest to throw an Exception from constructor

public class Person
{


    int age;
    public Person(int age) throws Exception
    {
       if(age <= 0)
       {

          throw new Exception("Age is not allowed");
       }
       // Do some stuffs
       this.age = age;
    }

}

Edit:

You can also use IllegalArgumentException as suggested by Till Helge Helwig

public class Person
{


    int age;
    public Person(int age) throws IllegalArgumentException
    {
       if(age <= 0)
       {

          throw new IllegalArgumentException("Age is not allowed");
       }
       // Do some stuffs
       this.age = age;
    }

}
  • 3
    I would suggest throwing an `IllegalArgumentException` and make it a checked one, too. – Till Helge Jan 18 '13 at 07:59
  • Thanks. Is there any other way besides Exception throwing and handling ? – FirstName LastName Jan 18 '13 at 07:59
  • 1
    @FirstNameLastName Aside from your own solution using a factory...not that I know of...because there is no other way to prevent a constructor from creating an instance. Worst case then would be that you get an instance that violates your class invariant. – Till Helge Jan 18 '13 at 08:02
  • I'm not sure, that throwing an exception from the constructor is a good idea – Andremoniy Jan 18 '13 at 08:11
  • 1
    @Andremoniy why not? The JDK makes heavy use of that! – Fildor Jan 18 '13 at 08:29
  • @Flidor, well, in such kind of domain as `Person` bean could be a lot of parameters which should be checked. Will you produce a lot of telescopic constructors with sophisticated checks and throwing exceptions? Static factory, or `Builder` pattern will work here more better. Furthermore, using constructor you aren't able to return `null` value (it could be needed in some situations). – Andremoniy Jan 18 '13 at 08:34
  • 1
    @Andremoniy We didn't talk about Beans. It was all about POJOs. I do not work with Beans but isn't one of their key features to not have constructor-params at all? So my understanding is that using Beans you do not have the option to throw Exceptions because of illegal args in the constructor. If your requirement is to be able to have null values if args do not meet certain criteria, then that another question but based on the requirement. Not because throwing exceptions from the ctor is generally a bad idea. – Fildor Jan 18 '13 at 09:18
6

Consider this example, this is java.util.HashMap implementation

public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);

    // Find a power of 2 >= initialCapacity
    int capacity = 1;
    while (capacity < initialCapacity)
        capacity <<= 1;

    this.loadFactor = loadFactor;
    threshold = (int)(capacity * loadFactor);
    table = new Entry[capacity];
    init();
}

see more in Effective Java 2nd Edition, Item 38: Check parameters for validity by Joshua Bloch, who is also the author of the above code

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
3

It will be better to use the static factory for this purposes. Because throwing an exception from a constructor is not very nice idea.

public class Person
{     
    public static Person newPerson(int age) /* throws SomeException -- if you want */ {
        if (age <= 0 || age >= 150) {
           return null; // or throw an Exception - it is how you want   
        }
        return new Person(age);
    }

    private Person(int age) {
        // assign age to field value
    }
}
Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • 2
    What's the difference of throwing the exception from parameterized constructor and throwing it from a factory method (if he wants to)? – Fildor Jan 18 '13 at 09:44
  • 1
    In my case Java doesn't even try to create object. On some JVM implementations the fact of constructor calling leads to memory allocation for an object. In common case this could lead to insignificant increasing of GC work, I think. – Andremoniy Jan 18 '13 at 09:49
  • Ah, I see. Could be indeed significant. Depends on how frequently you do this :) – Fildor Jan 18 '13 at 10:16
  • 1
    @Andremoniy - can you give me some links which show that different JVMs allocate memory for a constructor call and how this affects code performance ? – FirstName LastName Mar 22 '13 at 01:39
1

Rather throw Exception if parameter is illegal.

public Test(int age) throws IllegalArgumentException {
    if(age<0)
        throw new IllegalArgumentException(...);
    this.age = age;
}
Subhrajyoti Majumder
  • 40,646
  • 13
  • 77
  • 103