Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate constructor parameters on Java?

Let's say we use Java SE (no libraries) and have the following situation. We have a class:

public class DriverInfo {
    private final int age;

    public DriverInfo(int age) {
        this.age = age;
    }

    // getter here
}

In some countries there is a requirement that you can drive if you're 18 years old. In other words - we need to have some validation for age parameter. Something like:

if (age < 18) {
    throw new IllegalArgumentException("Age is not valid!");
}

So, my question is - where this validation should be? My thoughts are as follows:

  • On constructor add the if() described above. The validation would work if the constructor is called from multiple places on your code. My concern is that class constructors should (IMHO) not contain any logic. Am I right?
  • Validate somewhere outside the constructor - whether it's a factory method, builder class etc. But then we are forcing developers to not instantiate the class by using the constructor, but to use some artificial factory/builder.
  • To validate constructors parameters by using Validate. It's not standard Java, but I saw people doing this. As for me it doesn't look right, because we're adding logic to the constructor - which doesn't look right for me.
  • Any other good way I missed?

Any thoughts would be highly appreciated. Does anyone could suggest a best practice how to deal with the situation described abode?

like image 754
Ernestas Kardzys Avatar asked Jul 15 '26 05:07

Ernestas Kardzys


2 Answers

Validation in constructor is completely fine. This "no logic in constructor" rule does not apply on it, guess it's worded bit unfortunately. Task of constructor is to take dependencies from outside (dependency injection), make sure they are valid and then probably store them in instance attributes - creating valid instance in short.

This way the rules of what is valid and what is not valid are kept inside the object, not detached in some factory.

If the instance would be invalid, then throwing an exception, which explains what is wrong with parameters, is absolutely fine. It prevents invalid instances from roaming around system.

Also this way with immutable objects you get guaranteed that all existing instances are valid all the time, which is great.

Having some validation method on the object is possible and can be useful, but I'd prefer constructor validation any day. But if it's not possible, then it's better than nothing and it still keeps the rules for validity within the object. Like when some framework constructs your mutable object for you and requires parameterless constructor...you can forget to call it, but it's better than nothing.

like image 60
Igand Avatar answered Jul 17 '26 19:07

Igand


I think you can "also" use Builder pattern for such use cases. Although Constructor validation is perfectly fine and usually Builder tend to introduce a lot of Boiler Plate code but if you want to avoid validation inside the constructor and also want to have immutable class (no setter validations) then you can give builders a try.

Usually builders should be used when faced with many constructor parameters. You can read more on builders here.

public class DriverInfo {

    private final int age;

    //more parameters here

    private DriverInfo(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public static DriverInfoBuilder newBuilder() {
        return new DriverInfoBuilder();
    }

    public static final class DriverInfoBuilder {

        private int age;

        private DriverInfoBuilder() {
        }

        public DriverInfoBuilder age(int age) {
            this.age = age;
            return this;
        }

        public DriverInfo build() {
            if (age < 18) {
                throw new IllegalArgumentException("Age is not valid!");
            }

            //other validations.

            return new DriverInfo(age);
        }
    }
}

Again there are many ways to do this and there is no right and wrong here. Its more about what one prefers and will it be readable for other programmers or not.

like image 34
Sneh Avatar answered Jul 17 '26 19:07

Sneh