local variable cannot be assigned as final - java

I have a variable that asks me to make it final, but when making it final I get an error that says the following: "The final local variable "enter" cannot be assigned, since it is defined in an endclosing type"
How could you declare such a variable?
void yyyyyy(ActionEvent event){
final Scanner enter = null;
try{
.
.
.
enter = new Scaner(xxxxx);
}catch(){
....
}finally{
if(enter != null){
}
}

Right now you declare the variable and initialize it in the same time. Since it's final, you can not assign values to it more, than once.
If you remove assignment from initialization, you still can not make this variable final, because you check it for null in finally block. For that logic to work, variable should be assigned null explicitly somewhere. And that's impossible, because try block could throw an exception in the first line.
Whatever asks you to make the variable final - ignore it.

You can make it work like this. As some other answers are explaining, you can't assign value for final variable twice.
You can make it work like this
void yyyyyy(final ActionEvent event) {
Scanner enter = null;
try {
enter = new Scanner("/");
} catch (final Exception exception) {
} finally {
enter.close();
}
}

Related

How would I effectively use a lambda to iterate through an Iterable data structure and compare the values to local variables [duplicate]

I have a JavaFX 8 program (for JavaFXPorts cross platfrom) pretty much framed to do what I want but came up one step short. The program reads a text file, counts the lines to establish a random range, picks a random number from that range and reads that line in for display.
The error is: local variables referenced from a lambda expression must be final or effectively final
button.setOnAction(e -> l.setText(readln2));
I am a bit new to java but is seems whether I use Lambda or not to have the next random line display in Label l, my button.setOnAction(e -> l.setText(readln2)); line is expecting a static value.
Any ideas how I can tweak what I have to simply make the next value of the var readln2 display each time I press the button on the screen?
Thanks in advance and here is my code:
String readln2 = null;
in = new BufferedReader(new FileReader("/temp/mantra.txt"));
long linecnt = in.lines().count();
int linenum = rand1.nextInt((int) (linecnt - Low)) + Low;
try {
//open a bufferedReader to file
in = new BufferedReader(new FileReader("/temp/mantra.txt"));
while (linenum > 0) {
//read the next line until the specific line is found
readln2 = in.readLine();
linenum--;
}
in.close();
} catch (IOException e) {
System.out.println("There was a problem:" + e);
}
Button button = new Button("Click the Button");
button.setOnAction(e -> l.setText(readln2));
// error: local variables referenced from a lambda expression must be final or effectively final
You can just copy the value of readln2 into a final variable:
final String labelText = readln2 ;
Button button = new Button("Click the Button");
button.setOnAction(e -> l.setText(labelText));
If you want to grab a new random line each time, you can either cache the lines of interest and select a random one in the event handler:
Button button = new Button("Click the button");
Label l = new Label();
try {
List<String> lines = Files.lines(Paths.get("/temp/mantra.txt"))
.skip(low)
.limit(high - low)
.collect(Collectors.toList());
Random rng = new Random();
button.setOnAction(evt -> l.setText(lines.get(rng.nextInt(lines.size()))));
} catch (IOException exc) {
exc.printStackTrace();
}
// ...
Or you could just re-read the file in the event handler. The first technique is (much) faster but could consume a lot of memory; the second doesn't store any of the file contents in memory but reads a file each time the button is pressed, which could make the UI unresponsive.
The error you got basically tells you what was wrong: the only local variables you can access from inside a lambda expression are either final (declared final, which means they must be assigned a value exactly once) or "effectively final" (which basically means you could make them final without any other changes to the code).
Your code fails to compile because readln2 is assigned a value multiple times (inside a loop), so it cannot be declared final. Thus you can't access it in a lambda expression. In the code above, the only variables accessed in the lambda are l, lines, and rng, which are all "effectively final` as they are assigned a value exactly once. (You can declare them final and the code would still compile.)
The error you encountered means that every variable that you access inside a lambda expressions body has to be final or effectively final. For the difference, see this answer here: Difference between final and effectively final
The problem in your code is the following variable
String readln2 = null;
The variable gets declared and assigned later on, the compiler can not detect if it gets assigned once or multiple times, so it is not effectively final.
The easiest way to solve this is to use a wrapper object, in this case a StringProperty instead of a String. This wrapper gets assigned only once and thus is effectively final:
StringProperty readln2 = new SimpleStringProperty();
readln2.set(in.readLine());
button.setOnAction(e -> l.setText(readln2.get()));
I shortened the code to show only the relevant parts..
I regularly pass outer object into interface implementation in this way:
1. Create some object holder,
2. Set this object holder with some desired state,
3. Change inner variables in the object holder,
4. Get those variables and use them.
Here is one example from Vaadin :
Object holder :
public class ObjectHolder<T> {
private T obj;
public ObjectHolder(T obj) {
this.obj = obj;
}
public T get() {
return obj;
}
public void set(T obj) {
this.obj = obj;
}
}
I want to pass button captions externally defined like this :
String[] bCaption = new String[]{"Start", "Stop", "Restart", "Status"};
String[] commOpt = bCaption;
Next, I have a for loop, and want to create buttons dynamically, and pass values like this :
for (Integer i = 0; i < bCaption.length; i++) {
ObjectHolder<Integer> indeks = new ObjectHolder<>(i);
b[i] = new Button(bCaption[i],
(Button.ClickEvent e) -> {
remoteCommand.execute(
cred,
adresaServera,
comm + " " + commOpt[indeks.get()].toLowerCase()
);
}
);
b[i].setWidth(70, Unit.PIXELS);
commandHL.addComponent(b[i]);
commandHL.setComponentAlignment(b[i], Alignment.MIDDLE_CENTER);
}
Hope this helps..

In Java, Is it possible to return more than one value from try catch block?

I want to read the Id, name and score from console for another use. However these three variables are inside try-catch block scope. I wonder if there is any way I can get these three values return from try-catch.(If I don't want to put the three variables individually in three pairs of try-catch block) Thanks for the time.
Here is my sample code:
StuManage sm = new StuManage();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Please enter the student ID: ");
try {
String Id = br.readLine();
String name = br.readLine();
float score =Float.parseFloat(br.readLine());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Yes. Just declare the method as throws IOException and remove the try catch altogether.
yes , you can declare and initialize those to an invalid value
String id = null;
String name = null;
float score = 1.0f;
try {
id = br.readLine();
name = br.readLine();
score = Float.parseFloat(br.readLine());
} catch (IOException e) {
then you need to check after that try block which values are still holding and invalid initial value...
Just ensure that the variables are declared global to the method with their default values, that way it should be fine to access them throughout the method.
Another solution would be to remove the try/catch from the method and rather put the try/catch within the main method, that way you'll let the exception(s)(if any) bubble up to the main method and then handle them there, which you'll also benefit from because you no longer need to worry about scoping issues.
Easily you can't, Because try and catch block is for check block of code for errors, Because of that the block of code should't be accessible outside the try block to be truly tested.

local variables referenced from a lambda expression must be final or effectively final

I have a JavaFX 8 program (for JavaFXPorts cross platfrom) pretty much framed to do what I want but came up one step short. The program reads a text file, counts the lines to establish a random range, picks a random number from that range and reads that line in for display.
The error is: local variables referenced from a lambda expression must be final or effectively final
button.setOnAction(e -> l.setText(readln2));
I am a bit new to java but is seems whether I use Lambda or not to have the next random line display in Label l, my button.setOnAction(e -> l.setText(readln2)); line is expecting a static value.
Any ideas how I can tweak what I have to simply make the next value of the var readln2 display each time I press the button on the screen?
Thanks in advance and here is my code:
String readln2 = null;
in = new BufferedReader(new FileReader("/temp/mantra.txt"));
long linecnt = in.lines().count();
int linenum = rand1.nextInt((int) (linecnt - Low)) + Low;
try {
//open a bufferedReader to file
in = new BufferedReader(new FileReader("/temp/mantra.txt"));
while (linenum > 0) {
//read the next line until the specific line is found
readln2 = in.readLine();
linenum--;
}
in.close();
} catch (IOException e) {
System.out.println("There was a problem:" + e);
}
Button button = new Button("Click the Button");
button.setOnAction(e -> l.setText(readln2));
// error: local variables referenced from a lambda expression must be final or effectively final
You can just copy the value of readln2 into a final variable:
final String labelText = readln2 ;
Button button = new Button("Click the Button");
button.setOnAction(e -> l.setText(labelText));
If you want to grab a new random line each time, you can either cache the lines of interest and select a random one in the event handler:
Button button = new Button("Click the button");
Label l = new Label();
try {
List<String> lines = Files.lines(Paths.get("/temp/mantra.txt"))
.skip(low)
.limit(high - low)
.collect(Collectors.toList());
Random rng = new Random();
button.setOnAction(evt -> l.setText(lines.get(rng.nextInt(lines.size()))));
} catch (IOException exc) {
exc.printStackTrace();
}
// ...
Or you could just re-read the file in the event handler. The first technique is (much) faster but could consume a lot of memory; the second doesn't store any of the file contents in memory but reads a file each time the button is pressed, which could make the UI unresponsive.
The error you got basically tells you what was wrong: the only local variables you can access from inside a lambda expression are either final (declared final, which means they must be assigned a value exactly once) or "effectively final" (which basically means you could make them final without any other changes to the code).
Your code fails to compile because readln2 is assigned a value multiple times (inside a loop), so it cannot be declared final. Thus you can't access it in a lambda expression. In the code above, the only variables accessed in the lambda are l, lines, and rng, which are all "effectively final` as they are assigned a value exactly once. (You can declare them final and the code would still compile.)
The error you encountered means that every variable that you access inside a lambda expressions body has to be final or effectively final. For the difference, see this answer here: Difference between final and effectively final
The problem in your code is the following variable
String readln2 = null;
The variable gets declared and assigned later on, the compiler can not detect if it gets assigned once or multiple times, so it is not effectively final.
The easiest way to solve this is to use a wrapper object, in this case a StringProperty instead of a String. This wrapper gets assigned only once and thus is effectively final:
StringProperty readln2 = new SimpleStringProperty();
readln2.set(in.readLine());
button.setOnAction(e -> l.setText(readln2.get()));
I shortened the code to show only the relevant parts..
I regularly pass outer object into interface implementation in this way:
1. Create some object holder,
2. Set this object holder with some desired state,
3. Change inner variables in the object holder,
4. Get those variables and use them.
Here is one example from Vaadin :
Object holder :
public class ObjectHolder<T> {
private T obj;
public ObjectHolder(T obj) {
this.obj = obj;
}
public T get() {
return obj;
}
public void set(T obj) {
this.obj = obj;
}
}
I want to pass button captions externally defined like this :
String[] bCaption = new String[]{"Start", "Stop", "Restart", "Status"};
String[] commOpt = bCaption;
Next, I have a for loop, and want to create buttons dynamically, and pass values like this :
for (Integer i = 0; i < bCaption.length; i++) {
ObjectHolder<Integer> indeks = new ObjectHolder<>(i);
b[i] = new Button(bCaption[i],
(Button.ClickEvent e) -> {
remoteCommand.execute(
cred,
adresaServera,
comm + " " + commOpt[indeks.get()].toLowerCase()
);
}
);
b[i].setWidth(70, Unit.PIXELS);
commandHL.addComponent(b[i]);
commandHL.setComponentAlignment(b[i], Alignment.MIDDLE_CENTER);
}
Hope this helps..

Modifying boolean value in Action Listeners [duplicate]

This question already has answers here:
The final local variable cannot be assigned
(6 answers)
Closed 8 years ago.
Code:
final boolean saveedit = true;
btnSaveEdit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (saveedit) {
// save function
if (txtMessage.getText().length() != 0) {
message = txtMessage.getText();
}
// show popup
JOptionPane.showMessageDialog(frmEventsAndProperties,
"Your last message is: " + message, "Message",
JOptionPane.PLAIN_MESSAGE);
btnSaveEdit.setText("Edit");
txtMessage.setEnabled(false);
saveedit = false;
} else {
// edit function
}
}
});
Error:
'The final local variable saveedit cannot be assigned, since it is defined in an enclosing type'.
Question:
I have seen other solutions for similar same errors, yet there must be a simple way to implement it - probably as simple as defining something earlier or moving it around.
I would appreciate any help.
Wherenver you want to use a variable inside an inner class (here ActionListener), you have two choices (regarding how you want to use it, modify(mutate) or access):
Using the final keyword with a local variable (it is not recommended for your case, since you want to modify your variable inside the inner class, not access only)
Using a field vairable, that need not be final (it is recommended)
As I mentioned, the seconed solution is feasible for you, since you want to do saveedit = false; which is mutating.
I completely agree with sager89. But i want to add one thing here which is.
If the keyword final is used for an instance variable, Then the final variable can be assigned only once and at the time of declaration or you will have to assign it in each and every constructor once.
This question is not a duplicate, the answer is for anyone wondering to simply move
final boolean saveedit = true;
to inbetween these lines:
btnSaveEdit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
That way it is not defined in an enclosing type :)

Problems initializing a final variable in Java

I keep running into slight variations of a problem in Java and it's starting to get to me, and I can't really think of a proper way to get around it.
I have an object property that is final, but dynamic. That is, I want the value to be constant once assigned, but the value can be different each runtime. So I declare the class level variable at the beginning of the class - say private final FILE_NAME;. Then, in the constructor, I assign it a value - say FILE_NAME = buildFileName();
The problem begins when I have code in the buildFileName() method that throws an exception. So I try something like this in the constructor:
try{
FILE_NAME = buildFileName();
}
catch(Exception e){
...
System.exit(1);
}
Now I have an error - "The blank final field FILE_NAME may not have been initialized." This is where I start to get slightly annoyed at Java's strict compiler. I know that this won't be a problem because if it gets to the catch the program will exit... But the compiler doesn't know that and so doesn't allow this code. If I try to add a dummy assignment to the catch, I get - "The final field FILE_NAME may already have been assigned." I clearly can't assign a default value before the try-catch because I can only assign to it once.
Any ideas...?
How about
String tempName = null;
try{
tempName = buildFileName();
}
catch(Exception e){
...
System.exit(1);
}
FILE_NAME = tempName;
Either
try {
FILE_NAME = buildFileName();
} catch (Exception e){
...
System.exit(1);
throw new Error();
}
Or some prefer:
private static final String FILE_NAME = fileName();
private static String fileName() {
try {
return buildFileName();
} catch (Exception e){
...
System.exit(1);
throw new Error();
}
}
But calling System.exit in a static initialiser is probably a bad idea. It's going to mess your unit tests up.
On second thought, I think I just came up with a solution! - use an intermediate variable.
String fileName = null;
try{
fileName = buildFileName();
}
catch(Exception e){
...
System.exit(1);
}
FILE_NAME = fileName;
Don't know why it took me so long to think of this...
I would personally just throw an Error -- if your error flow is properly designed, the System.exit() should be redundant. Your program presumably doesn't plough on into the wilderness if an Error is thrown...?
Along the same lines as the OP's issue, I had to be able to find a way to assign values to final fields to be read in from a .properties file on the filesystem, so the values couldn't be known by my app until that happened. Using a generalized method call to assign the value after reading the content of the .properties file into a Properties object on app startup was a Hail Mary pass that thankfully worked out. It also limits the no. of times the file has to be read to once per the app's getting loaded into the memory simply by the code checking to see if the Properties object is or is not currently null. But of course, once assigned, the final field's value cannot be altered except by altering its "final" status via manuipulating the field's modifying definition at runtime (as discussed in some other places here on SO, such as https://stackoverflow.com/a/3301720/1216686 - sneaky, but I love it!). Code example, with typical runtime error checking such as for NPEs omitted for brevity:
import java.util.Properties;
public class MyConstants {
private static Properties props; // declared, not initialized,
// so it can still be set to
// an object reference.
public static String MY_STRING = getProperty("prop1name", "defaultval1");
public static int MY_INT = Integer.parseInt(getProperty("prop2name", "1"));
// more fields...
private static String getProperty(String name, String dflt) {
if ( props == null ) {
readProperties();
}
return props.getProperty(name, dflt);
}
private static void readProperties() {
props = new Properties(); // Use your fave way to read
// props from the file system; a permutation
// of Properties.load(...) worked for me.
}
// Testing...
public static void main(String[] args) {
System.out.println(MY_STRING);
System.out.println(MY_INT);
}
}
This lets you externalize properties to be read into the app and still mark the fields used to hold their values as "final". It also allows you to guarantee a returned value for the final field value since getProperty() in the Properties class allows the method's calling code to pass in a default value to use in case the property's key-value pair wasn't found in the external .properties file.

Categories

Resources