4

I have some code like so:

public class Foo {
    private int x;

    public Foo() {
    }

    public Foo(int x) {
        try {
            //do some initialisation stuff like:
            this.x = x;
        }
        catch(Exception ge){
            //call empty constructor not possible
            //this();
            //this.EMPTY();
            //Foo();
        }
    }

    public static final Foo EMPTY = new Foo();
}

I'd like to know if it is possible to achieve something such as this (I know that calling another constructor must be the first statement in the constructor). I have looked around here on SO but haven't found anything as such, leading me to believe that perhaps, I ought to handle the error logic in the instantiating method.

Dark Star1
  • 6,986
  • 16
  • 73
  • 121

4 Answers4

3

Just change the execution order :

public class Foo {

    Integer i;
    public Foo() {
        System.out.println("Empty constructor invoked");
    }

    public Foo(Integer i) {

        this(); //can be omitted

        try {
            System.out.println("i initialized to : "+i.toString());

        } catch (Exception ex) {

            System.out.println("i NOT initialized ");
        }
    }


    public static void main(String[] args) {

        new Foo(); //prints: Empty constructor invoked

        new Foo(5);//prints: Empty constructor invoked
                   //prints: i initialized to : 5

        new Foo(null);//prints: Empty constructor invoked
                   //prints: i NOT initialized 
    }
}
c0der
  • 18,467
  • 6
  • 33
  • 65
  • 1
    The only problem with that approach is that if in the `try` section he initialise 2 or more members. The exception can happen in the middle leaving some of the members with default values and some with overwritten values. – Roee Gavirel Jun 26 '17 at 13:10
2

In general, it isn't great practice to call code which could throw in a constructor, and worse then suppress the exception from the caller altogether. However, what you could do is refactor your code so that you move the 'default' initialization of the parameterless constructor into a helper method, which you can then call from your exception handler in the second constructor:

public class Foo {
    private int x;

    public Foo() {
      doDefaultInitialize();
    }

    public Foo(int x) {
        try {
          // dodgy code which could throw
        }
        catch(Exception ge){
          doDefaultInitialize();        
        }
    }

    private void doDefaultInitialize() {
       // Fallback initialization goes here
       x = 42;
    }
}        
StuartLC
  • 104,537
  • 17
  • 209
  • 285
2

As you said

calling another constructor must be the first statement in the constructor

There are 2 solution I usually use when I need this behavior:

  1. Make an init function and call it from both places:

    public class Foo {
        private int x;
    
        public Foo() {
            init();
        }
    
        public Foo(int x) {
            try {
                //do some initialisation stuff like:
                this.x = x;
            }
            catch(Exception ge){
                init();
            }
        }
    
        private init() {
            //Do the default initialization here...
        }
    
        public static final Foo EMPTY = new Foo();
    }
    
  2. Make a static function to initialize the object and return it.

    public class Foo {
        private int x;
    
        private Foo() {
            this.x = 42;
        }
    
        private Foo(int x) throws Exception {
            //do some initialization stuff like:
            this.x = x;
        }
    
        public static Foo getNewInstance(int x) {
            try {
                return new Foo(x);
            } catch (Exception e) {
                return new Foo();
            }
        }
    
        public static final Foo EMPTY = getNewInstance();
    }
    
Roee Gavirel
  • 18,955
  • 12
  • 67
  • 94
1

Just do nothing in the catch block in the constructor. It should work as you want. However, do have a look at this try-catch-in-constructor-recommended-practice for choosing the right approach to your problem.

Also, if you are doing any default initializations, then follow the approach mentioned by @StuartLC

phoenixSid
  • 447
  • 1
  • 8
  • 22