Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Constructor call must be the first statement in a constructor" issue in Java [duplicate]

Possible Duplicate:
Why does this() and super() have to be the first statement in a constructor?

I'd like to have constructor chain in Java. For example, with the first constructor I have a string as a parameter, and call the second constructor as I create an object from the parameter string.

public class IMethodFinder {
    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        IJavaProject javaProject = JavaCore.create(project);
        this(javaProject, methodName, numberOfParameters);
    }

    public IMethodFinder(IJavaProject javaProject, String methodName,
        int numberOfParameters) {
        ... 
    }
}

However, I got an error "Constructor call must be the first statement in a constructor" error.

enter image description here

I made a common code that is shared between the two constructors, but I'm not sure this is the only solution to bypass the issue.

public class IMethodFinder {
    public IMethodFinder(IJavaProject javaProject, String methodName,
            int numberOfParameters) {
        dosomething(javaProject, methodName, numberOfParameters);
    }

    public IMethodFinder(String projectName, String methodName,
            int numberOfParameters) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        IJavaProject javaProject = JavaCore.create(project);
        dosomething(javaProject, methodName, numberOfParameters);
    }

    private void dosomething(IJavaProject javaProject, String methodName,
            int numberOfParameters)
    {
       ...  
    }

}
  • Why does Java require constructor call as the first statement? What's the idea behind this requirement?
  • What is Java's convention for my case? Is the calling common method a good way to go?
like image 543
prosseek Avatar asked Dec 28 '12 16:12

prosseek


2 Answers

There is no intrinsic reason why Java could not be extended to allow statements that do not access this before the constructor. However, that would add to the language complexity and obscure the code when used (particularly when you consider the call may be implicit).

Generally you want to keep constructors as simple as possible. init() methods are a bad idea as they prevent the use of final. It appears that the code is accessing a mutable static which is a really bad idea.

For your specific code, you can write:

    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        this(
            JavaCore.create(
                ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)
            ),
            methodName,
            numberOfParameters
        );
    }

A more general hack is to call a static method within the call to the constructor:

public class IMethodFinder {
    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        this(createProject(projectName), methodName, numberOfParameters);
    }

    public IMethodFinder(IJavaProject javaProject, String methodName,
        int numberOfParameters) {
        ... 
    }

    private static IJavaProject createProject(String projectName) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        IJavaProject javaProject = JavaCore.create(project);
        return javaProject;
    }
}

Edit March 2018: In message Records: construction and validation Oracle is suggesting this restriction be removed (but unlike C#, this will be definitely unassigned (DU) before constructor chaining).

Historically, this() or super() must be first in a constructor. This restriction was never popular, and perceived as arbitrary. There were a number of subtle reasons, including the verification of invokespecial, that contributed to this restriction. Over the years, we've addressed these at the VM level, to the point where it becomes practical to consider lifting this restriction, not just for records, but for all constructors.

like image 72
Tom Hawtin - tackline Avatar answered Oct 26 '22 15:10

Tom Hawtin - tackline


Solution 1: Your constructors should have a more well-directed flow to avoid using a common init. Quite often one constructor will be more basic and construct a complete valid object, then the outer constructor can decorate this.

Solution 2: It is often good practice to use a static factory method, that for instance can handle the preprocessing you need here. This looks like a good use case for this pattern.

Solution 3: Instead of a common init method just have static methods that do the isolated preprocessing for you. e.g. myField = processInputField(myField). Common init methods play very poorly with final fields which is a stronger reason they are bad practice - essentially, yes, constructors should do the complete work of constructing.

like image 38
djechlin Avatar answered Oct 26 '22 14:10

djechlin