1

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?

Community
  • 1
  • 1
Farshad
  • 3,074
  • 2
  • 30
  • 44
  • 2
    Possible duplicate of [Why does this() and super() have to be the first statement in a constructor?](http://stackoverflow.com/questions/1168345/why-does-this-and-super-have-to-be-the-first-statement-in-a-constructor) – CollinD Jul 14 '16 at 18:02
  • 1
    Don't put such resource intensive logic in the constructor. Make a lightweight constructor and a separate `init()` method to do the heavy lifting. – azurefrog Jul 14 '16 at 18:03
  • @azurefrog so when I use init() I still must call the parent constructor at first place – Farshad Jul 14 '16 at 18:12
  • 2
    @CollinD, this is not exactly a duplicate. It doesn't ask *why*. It just asks for a way to get around this, and for a sane reason too. – Sergei Tachenov Jul 14 '16 at 18:13
  • 1
    @CollinD I already mentioned the link you commented if you read my post! I'm asking for the ways that I can handle this situation, Not trying to bypass it. – Farshad Jul 14 '16 at 18:14

2 Answers2

10

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.

Sergei Tachenov
  • 24,345
  • 8
  • 57
  • 73
  • Thanks, this is exactly what I was looking for – Farshad Jul 14 '16 at 18:11
  • What if number of arguments of subclass and superclass constructor don' match? Is your solution working in this scenario as well or I should use a builder method like Cyril answer ? – Farshad Jul 14 '16 at 18:32
  • 1
    @FarShaD, well, technically it can work, but will look ugly. Will add an example in a moment. – Sergei Tachenov Jul 14 '16 at 18:37
3

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.

Cyril
  • 2,376
  • 16
  • 21