usertest usertest - 6 months ago 10
Java Question

java: NullPointerExc why a List contains the added object when a lambda expression is invoked directly on it. and Not when the lambda is a method

I have JavaFX form, user can choose an image. the image is stored in an ArrayList, because I cannot assign it directly to an Image field inside the lambda expression

List<ImageByteInfo> imageBinary = new ArrayList<>();
imageBinary.add(null);//for create button test, null is a valid parameter
chooseImage.setOnAction((ActionEvent e) -> {
File selectedFile = logoChooser.showOpenDialog(stage);
if (selectedFile != null) {
Image logo = new Image("file:" + selectedFile.getAbsolutePath());
imageBinary.clear();
imageBinary.add(ImageConverter.imageToByteArray(logo));
System.out.println("list image first entry, INSIDE: " + imageBinary.get(0));//working
previewLogo.setImage(logo);
}
});


so when the user finish entring all fields, I invoke a createButton, the problem is here, when I try to get the stored object in
imageBinary
List, directly in setOnAction() method. it works and get the object.

createButton.setOnAction((ActionEvent e) -> {
System.out.println("list image first entry, Outside: " + imageBinary.get(0));
});


But What I want to do is invoke a method that holds the content of this lambda expression, so I do this:

createSchoolButton.setOnAction(createBtnFire(
nameInput.getText(), ..,
imageBinary.get(0),
.., zipInput.getText()));


this is createBtnFire()

private EventHandler<ActionEvent> createBtnFire(String name, ..
ImageByteInfo logo, boolean addressEntered, String... addressFields) {
EventHandler<ActionEvent> createBtn = (ActionEvent e) -> {
//code..
entity.setCreationDate(creationDate);//null
System.out.println(logo);//this print null, so next line throws a NullPointerException
entity.setImageByteInfoEntity(new ImageByteInfoEntity(logo.getByteImage(), logo.getWidth(), logo.getHeight()));
//code..
startUI.continueToMainContent();
};
return createBtn;
}


==> NullPointerException at
entity.setImageByteInfoEntity(..);

I did make the list an instance variable, still null. So why when I don't use a method for the lambda expression it works and the list returns the object and when I use the method it returns null. Thanks.

Answer

This has to do with the scope of the lambda expression. Think of a lambda expression as an anonymous inner class. When the code fragment that defines the lambda is run, this lambda object is created. As it can hold references to variables outside the lambda expression they are initiated as well.

Therefore when using the lambda expression like the first variant, the reference to imageBinary is used and the first element of the list is accessed when the lambda expression is run.

In the second case you define an event handler and pass the first element of imageBinary into it, which at that point is still not initialized.

You can change the createBtnFire in the following way, so it behaves in the same manner:

private EventHandler<ActionEvent> createBtnFire(String name, ..
         List<ImageByteInfo> logos, boolean addressEntered, String... addressFields) {
    EventHandler<ActionEvent> createBtn = (ActionEvent e) -> {
        //code..
        entity.setCreationDate(creationDate);//null
        ImageByteInfo logo = logos.get(0);
        System.out.println(logo);
        entity.setImageByteInfoEntity(new ImageByteInfoEntity(logo.getByteImage(), logo.getWidth(), logo.getHeight()));
        //code..
        startUI.continueToMainContent();
    };
    return createBtn;
}
Comments