简体   繁体   中英

Check conditions in subclass before calling superclass constructor method

As we know in the constructor body of a subclass, the parent constructor must be the first statement otherwise we get a compile time error, This topic is already discussed here .

Let's assume that calling the parent constructor causes a heavy cost of system resources, In other hand in the subclass constructor we need to check some conditions first, if the conditions are satisfied we're good to go through the parent constructor else there's no need to go further (let's say throw an exception):

class parent {
    parent(Object blah) {
        //Heavy resource consuming tasks
    }
}

class child extends parent {
    child(Object blah, boolean condition) {
        if (!condition) throw new IllegalArgumentException("Condition not satisfied");
        super(blah); //Compile error!
    }
}

If someone had the same issue I'm curious is there anyway to handle this situation or I must call the parent constructor first no matter how much resources it wastes and then throw the exception?

You could do something like this:

public class Jlaj extends ArrayList<String> {

    public Jlaj(int capacity) {
        super(checkCapacity(capacity));
    }

    private static int checkCapacity(int capacity) {
        if (capacity > 1000)
            throw new IllegalArgumentException();
        return capacity;
    }

    public static void main(String[] args) {
        new Jlaj(1001); // this throws IAE all right
    }
}

Note that you can only call static methods in this fashion, and that's good: calling instance methods on a partially initialized object is already a huge trouble, calling them even before superclass constructors would be a nightmare.

Now what if you need to check some other arguments that you don't pass to the superclass? You could do something like this then:

public class Jlaj extends ArrayList<String> {

    private final Object foo;

    public Jlaj(int capacity, Object foo) {
        super(checkArgumentsAndReturnCapacity(capacity, foo));
        this.foo = foo;
    }

    private static int checkArgumentsAndReturnCapacity(int capacity, Object foo) {
        if (capacity > 1000)
            throw new IllegalArgumentException();
        if (foo == null)
            throw new NullPointerException();
        return capacity;
    }

    public static void main(String[] args) {
        new Jlaj(1000, null); // throws NPE
    }
}

It works, but looks a bit ugly. You're passing two unrelated things into a function that returns just an argument for the superclass. At least the descriptive name somewhat compensates for that.

if you absolutely need to do this, you can create a static builder method with a private constructor:

class child extends parent {
    private child(Object blah) {
        super(blah);
    }

    static child create(Object blah, boolean condition) {
        if (!condition) throw new IllegalArgumentException("Condition not satisfied");

        return new child(blah);
    }


    public static void main(String[] args) {
        child a = child.create("a", true);
    }
}

I'm not a fan of a separate init method because you will end up with invalid state if you forget to call it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM