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.
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.Frame ob=new Frame();
you create an instance of your class and never use it again, why?frame.setLayout(null);
NEVER, please don't usenull-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..setBounds(...)
on every component, again, this is due tonull-layout
but it's better to use Layout managersfinal JTextField name=new JTextField();
There's no need to declare any of your components asfinal
, this is due to a poor design of your class, your components should be declared as class members (outside any method includingmain
).Speaking about
main
, separate your program into smaller pieces, don't throw everything atmain
or at the very least create a method that is notstatic
so you can call it after creating an instance of your class (or else later on you'll end up with tons ofstatic
variables and that's a poor design of your class once again).System.exit(0);
it will stop the JVM, it's never a good idea to do that, it's better to.dispose()
theJFrame
and have yourJFrame
'sdefaultCloseOperation
set toEXIT_ON_CLOSE
which will safely dispose your app and then stop the JVM.display=name.getText();
, for this particular case,display
could be an inner variable rather than a class member. This will solve your particular questionJOptionPane.showMessageDialog(null, "Hi "+ display);
thatnull
should be a reference to yourJFrame
, this will place your dialog in the middle of thatJFrame
rather than in the middle of the screen.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.
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 JPanel
s 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 passedcalTz
and you don't use it in this method - You always return
null
, why don't you setvoid
as return type?
Hope also these tips helps you to improve.
Related Topics
Admob No Fill from Ad Server - Failed to Load Ad: 3
Check Date Between Two Other Dates Spring Data Jpa
Tomcat Is Running But 8080 Port Is Not Responding
What Is the Most Elegant Way to Check If All Values in a Boolean Array Are True
Wait Until All Threads Finish Their Work in Java
Set Current Timezone to @Jsonformat Timezone Value
How to Use Junit to Test Asynchronous Processes
Get Current Week Start and End Date in Java - (Monday to Sunday)
Java Sorting a 2D Array Rows into Ascending and Columns into Descending Order
How to Replace a Placeholder in a String With a Simpledateformat Pattern
How to Mock Classes With Constructor Injection
How to Solve Liquibase Checksum Validation Fail After Liquibase Upgrade
Java.Lang.Noclassdeffounderror: Org/Json/Simple/Parser/Parseexception With Eclipse and Spring
Consider Defining a Bean of Type in Your Configuration