Java 8 Shows This Error. Local Variable Itemlist Defined in an Enclosing Scope Must Be Final or Effectively Final

Java 8 shows this error. Local variable itemList defined in an enclosing scope must be final or effectively final

You are using itemList within a lambda expression. Therefore it has to be final.

Java 8 introduces the new concept of effectivly final, which means, the compiler checks, if a used variable is final in usage and does not force the developer to explicitly declare it as final.

So if you change your code to

final List<RestaurantOrderBook> itemList = new ArrayList<RestaurantOrderBook>();

you will see, that the compiler gives you an error at:

itemList = mongoTemplate.find(query, RestaurantOrderBook.class);

because you are reasigning itemList. That is why itemList is not effectivly final as well. If you squash these two lines to

List<RestaurantOrderBook> itemList = mongoTemplate.find(query, RestaurantOrderBook.class);

it should work.

Local variable i defined in an enclosing scope must be final or effectively final

Can you give me some advice how I can fix this issue, please?

Why does this happen? You can read about it here: Lambdas: local variables need final, instance variables don't

Minimal changes to solve your problem: Don't use the i variable itself. Create a copy of it and make it final.

final int iCopy = i;
Optional<RiskFilters> filter_payload = filterList.stream().filter(f -> newFiltersPositionsList.get(iCopy).getId() == f.getId()).findAny();

For example can I skip the for cycle and use maybe stream into stream?

You could give it a try:

// replace the for-loop

// or just.... `newFiltersPositionsList.forEach(/* ... */)`
newFiltersPositionsList.stream().forEach(filterPosition -> {
Optional<RiskFilters> filter_payload = filterList.stream()
.filter(f -> filterPosition.getId() == f.getId())
.findAny();
RiskFilters filter = filter_payload.get();

filter.setPosition(filterPosition.getPosition());
riskFilterService.save(filter);
});

Also, you could use a for-each instead of a for-loop:

for (ChangeOrderRiskFiltersDTO filterPosition : newFiltersPositionsList) {
Optional<RiskFilters> filter_payload = filterList.stream()
.filter(f -> filterPosition.getId() == f.getId())
.findAny();
RiskFilters filter = filter_payload.get();
filter.setPosition(filterPosition.getPosition());
riskFilterService.save(filter);
}

Local variable list defined in an enclosing scope must be final or effectively final

Since stock service returns a list, why not just do the following:

    List<Stock> stockList = new ArrayList<>();

executor.submit( ()-> {
List<Stock> temp = stockService.getAllStocks());
stockList.addAll(temp);
//now that it's copied, submit to the executor.
return temp;
});

Since stockList is a reference, you are not changing the reference but only what stockList refers to. So you would not be violating the effectively final requirement. Note: Since the executor service returns immediately there may be a time delay before the list gets populated.

Getting local variable defined in the enclosing scope must be final or effective final

Try replacing this:

Package entitlePackage = new Package();
if(null != entitleProduct && null != entitleProduct.getPackages() && !entitleProduct.getPackages().isEmpty()) {
entitlePackage = entitleProduct.getPackages().stream().filter(
entitlePack ->
entitlePack.getName().equalsIgnoreCase(productPack.getPack().getPackageName()))
.findAny().orElse(null);
}

by this:

Package entitlePackage =
Optional.ofNullable(entitleProduct)
.map(Product::getPackages)
.map(Collection::stream)
.orElse(Stream.empty())
.filter(e -> productPack.getPack()
.getPackageName()
.equalsIgnoreCase(e.getName()))
.findAny()
.orElseGet(Package::new);

The entitlePackage will be effectively final. Also your code will be much easier to read and maintain.

Java: Local variable mi defined in an enclosing scope must be final or effectively final

The error means you cannot use the local variable mi inside an inner class.


To use a variable inside an inner class you must declare it final. As long as mi is the counter of the loop and final variables cannot be assigned, you must create a workaround to get mi value in a final variable that can be accessed inside inner class:

final Integer innerMi = new Integer(mi);

So your code will be like this:

for (int mi=0; mi<colors.length; mi++){

String pos = Character.toUpperCase(colors[mi].charAt(0)) + colors[mi].substring(1);
JMenuItem Jmi =new JMenuItem(pos);
Jmi.setIcon(new IconA(colors[mi]));

// workaround:
final Integer innerMi = new Integer(mi);

Jmi.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
IconA icon = (IconA) item.getIcon();
// HERE YOU USE THE FINAL innerMi variable and no errors!!!
Color kolorIkony = getColour(colors[innerMi]);
textArea.setForeground(kolorIkony);
}
});

mnForeground.add(Jmi);
}
}

Java8 Stream compiler message -- local variable must be final or effectively final

Like anonymous inner classes, lambda expressions can only access local variables if they are final or "effectively final" (Java 8 or higher; not final but never changed once assigned).

This is covered by the JLS, Section 15.27.2:

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.

Any local variable used but not declared in a lambda body must be definitely assigned (§16 (Definite Assignment)) before the lambda body, or a compile-time error occurs.

Similar rules on variable use apply in the body of an inner class (§8.1.3). The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems. Compared to the final restriction, it reduces the clerical burden on programmers.

Declare a final variable equal to i and use it.

for(int i = 0; i< 10; i++){
final int j = i;
correct = active
.stream()
.filter(f-> f.getAnswerScore().get(j).getStatus().equals(AnswerStatus.ANSWERED_CORRECT))
.count();
}

Cannot refer to the non-final local variable display defined in an enclosing scope

There are multiple issues with your code, and we'll address them right here, right now and solve your problem at the same time.

  1. public class Frame { this particular line has an error, Frame is the name of an AWT class, so it might confuse you or anyone who reads this code later on, give it a more meaningful name and avoid those names that could be confused with other Java packages.

  2. Frame ob=new Frame(); you create an instance of your class and never use it again, why?

  3. frame.setLayout(null); NEVER, please don't use null-layout, Swing has to deal with multiple PLAFs, screen sizes and resolutions, different OS, pixel perfect apps might seem like the easiest way to create complex UIs but later on you'll find that errors like this happen very often.

  4. .setBounds(...) on every component, again, this is due to null-layout but it's better to use Layout managers

  5. final JTextField name=new JTextField(); There's no need to declare any of your components as final, this is due to a poor design of your class, your components should be declared as class members (outside any method including main).

  6. Speaking about main, separate your program into smaller pieces, don't throw everything at main or at the very least create a method that is not static so you can call it after creating an instance of your class (or else later on you'll end up with tons of static variables and that's a poor design of your class once again).

  7. System.exit(0); it will stop the JVM, it's never a good idea to do that, it's better to .dispose() the JFrame and have your JFrame's defaultCloseOperation set to EXIT_ON_CLOSE which will safely dispose your app and then stop the JVM.

  8. display=name.getText();, for this particular case, display could be an inner variable rather than a class member. This will solve your particular question

  9. JOptionPane.showMessageDialog(null, "Hi "+ display); that null should be a reference to your JFrame, this will place your dialog in the middle of that JFrame rather than in the middle of the screen.

  10. You never place your program inside the EDT, see point #2 in this answer.

So, having all the above points in mind, here's an improved version of your code.

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class UsingVariablesInsideActionListenerExample {
//We declare our components here
private JFrame frame;
private JButton button;
private JTextField name;
private JTextField ohr;
private JLabel nameLabel;
private JLabel ohrID;
private JPanel pane;
private JPanel namePane;
private JPanel ohrPane;

public static void main(String[] args) {
SwingUtilities.invokeLater(new UsingVariablesInsideActionListenerExample()::createAndShowGUI); //This is using Java 8 lambdas to place your program in the EDT
}

private void createAndShowGUI() {
frame = new JFrame("Test"); //Create your JFrame

pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS)); //This will make this JPanel to arrange components vertically

namePane = new JPanel(); //By default, JPanels have FlowLayout which will arrange components horizontally
ohrPane = new JPanel();

name = new JTextField(10); //We create a JTextField with 10 columns
nameLabel = new JLabel("Name: ");
nameLabel.setForeground(Color.WHITE);

ohr = new JTextField(10);
ohrID = new JLabel("OHR ID: ");
ohrID.setForeground(Color.WHITE);

button = new JButton("Submit");

//Add the action listener
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
String display = name.getText(); //The display variable is now an inner variable rather than a class member
JOptionPane.showMessageDialog(frame, "Hi " + display);
frame.dispose(); //We dispose the JFrame and it will be closed after due to EXIT_ON_CLOSE below.
}
}
});

//We add the components to the namePane (horizontally), the order matters
namePane.add(nameLabel);
namePane.add(name);

//Now we add these components to the ohrPane (horizontally again)
ohrPane.add(ohrID);
ohrPane.add(ohr);

//We then add the name and ohr panes to a bigger JPanel (pane, which if you remember will add them vertically) and we add the button at the end
pane.add(namePane);
pane.add(ohrPane);
pane.add(button);

//We make them non opaque (transparent) so that we can see the background color of the JFrame
namePane.setOpaque(false);
ohrPane.setOpaque(false);
pane.setOpaque(false);

frame.add(pane);

frame.getContentPane().setBackground(Color.DARK_GRAY);
frame.pack(); //This will get every component's preferred size and make the JFrame as small as possible where it looks good on every OS, PLAF, screen size and resolution.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true); //We make the frame visible (always at the very end, when we've added everything to it).
}
}

And this is how it looks like now.

Sample Image

The UI may not be perfectly equal to the one you have, but I'm sure you can play with the different layout managers, and nest various JPanels to get a much better looking UI than mine, or at least a more similar one to the one you had.

Variable used in lambda expression should be final or effectively final

A final variable means that it can be instantiated only one time.
in Java you can't reassign non-final local variables in lambda as well as in anonymous inner classes.

You can refactor your code with the old for-each loop:

private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
try {
for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(calTz==null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}

Even if I don't get the sense of some pieces of this code:

  • you call a v.getTimeZoneId(); without using its return value
  • with the assignment calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue()); you don't modify the originally passed calTz and you don't use it in this method
  • You always return null, why don't you set void as return type?

Hope also these tips helps you to improve.



Related Topics



Leave a reply



Submit