
If you reached this article, you most likely face one of these errors, and trying to get rid of one, get another: "variable used in lambda expression should be final or effectively final", "variable may be not initialized", "cannot assign a value to final variable".
For my explanation I will use vaadin's Window.
public class SelectionWindow extends Window {
private Button okButton = null;
private BeanItemContainer container;
private LegalEntity selected;
public SelectionWindow(List items){
...
setClosable(false);
container = new BeanItemContainer<>(Entity.class, items);
grid = new Grid(container);
grid.addSelectionListener(event -> {
Object selectedObj = grid.getSelectedRow();
selected = (LegalEntity) selectedObj;
if (okButton != null) {
okButton.setEnabled(selected != null);
}
});
}
// the only way to close the window
public void setOkButtonListener(Button.ClickListener listener) {
okButton.addClickListener(listener);
}
// this way we get selected item
public Entity getSelected() {
return selected;
}
} |
public class SelectionWindow extends Window {
private Button okButton = null;
private BeanItemContainer container;
private LegalEntity selected;
public SelectionWindow(List items){
...
setClosable(false);
container = new BeanItemContainer<>(Entity.class, items);
grid = new Grid(container);
grid.addSelectionListener(event -> {
Object selectedObj = grid.getSelectedRow();
selected = (LegalEntity) selectedObj;
if (okButton != null) {
okButton.setEnabled(selected != null);
}
});
}
// the only way to close the window
public void setOkButtonListener(Button.ClickListener listener) {
okButton.addClickListener(listener);
}
// this way we get selected item
public Entity getSelected() {
return selected;
}
}
So, to pass params into the Window you just add arguments to the constructor. In my case I don't need a private field List items. If I did, I would add:
and a line to constructor:
You can use setters as well.
Case 1. You just need to read selected value and to use right in the code of the listener.
SelectionWindow selectionWindow = new SelectionWindow(items);
selectionWindow.setOkButtonListener(clickEvent -> {
Entity selected = selectionWindow.getSelected();
populateFromSelection(selected);
selectionWindow.close();
});
private void populateFromSingleSuggestion(LegalEntity legalEntity) {
// react upon the new value
} |
SelectionWindow selectionWindow = new SelectionWindow(items);
selectionWindow.setOkButtonListener(clickEvent -> {
Entity selected = selectionWindow.getSelected();
populateFromSelection(selected);
selectionWindow.close();
});
private void populateFromSingleSuggestion(LegalEntity legalEntity) {
// react upon the new value
}
The point is that you know in the code when your Window gets closed. On this event you can read any field/state from it (you can add getters) and update your UI.
Case 2. You want to read a value and assign to a variable with a wider scope. Use atomic reference.
final AtomicReference reference = new AtomicReference<>();
selectionWindow.setOkButtonListener(clickEvent -> {
reference.set(selectionWindow.getSelected());
selectionWindow.close();
}); |
final AtomicReference reference = new AtomicReference<>();
selectionWindow.setOkButtonListener(clickEvent -> {
reference.set(selectionWindow.getSelected());
selectionWindow.close();
});
Then get your item with reference.get().