Search code examples
javaclassconstructor

Constructor parameter becomes null inside class even though it is not in main in Java


I'm sorry if this is a dumb question but i'm pretty new to Java.

This is my main.java, I checked with a debugger and chosenFile is not null

import javax.swing.*;
import javax.swing.filechooser.*;
import java.io.File;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {

    public static void main(String[] args) {
        JFileChooser chooser = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter(
                "CSV Files", "csv");
        chooser.setFileFilter(filter);
        int returnVal = chooser.showOpenDialog(null);
        if (returnVal == JFileChooser.APPROVE_OPTION) {

            File chosenFile = chooser.getSelectedFile();
            // System.out.println(chosenFile.getAbsolutePath());
            if (chosenFile == null) {
                throw new NullPointerException("Null file in main");
            }
            questionAnswersInput inputFile = new questionAnswersInput(chosenFile); // Using a debugger I see that chosenFile is not null.
            System.out.println(inputFile);
        }
    }
}


In this questionAnswersInput.java class however inputFile becomes null and the exception is thrown only in the getPath() method.

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;

import javax.swing.*;
import java.io.*;

public class questionAnswersInput {
    final private File inputFile;

    public questionAnswersInput(File inputFile) {
        if (inputFile == null) {
            throw new IllegalArgumentException("Null file in constructor"); // Nothing happens here even tho inputFile is already null
        }
        System.out.println(inputFile.getAbsolutePath()); // This line doesnt execute
        this.inputFile = inputFile;
    }

    private String getPath() {
        System.out.println(inputFile);
        if (this.inputFile == null) {
            System.out.println("Ciao");
            throw new NullPointerException("Null file when getting path"); // This is the exception
        }
        return this.inputFile.getAbsolutePath();
    }

    private String path = getPath();


}


I've been trying to wrap my head around it for a while but I don't understand what the issue could be. Thanks in advance.


Solution

  • Java has an awful quirk which really frustrates people learning the language. When you create a class, the order of initialization is as follows:

    1. First, the constructor is invoked.
    2. The first instruction in the constructor is an explicit or implicit invocation to the super's constructor, so that one gets invoked.
    3. As soon as the super's constructor returns, every single field (member variable) of the current class gets initialized.
    4. Finally, the rest of the constructor gets to run.

    In your class you have an entirely superfluous private String path = getPath(); this forces getPath() to be invoked before your constructor has had a chance to execute this.inputFile = inputFile;, thus, inputFile is null in getPath().

    To solve this problem, you can do one of the following:

    • Get rid of the field initializer for path, (declare it uninitialized,) and then explicitly initialize it from within your constructor, after you have realized inputFile.

    • Get rid of path altogether, and replace it with invocations of getPath().