Why doesn't try-with-resources work with field variables? - java

This is my very first question on SO and I'm confused there isn't a similar question yet!
So the question is:
Why doesn't try-with-resources work with field variables?
Or in other words: Why do I always need a local variable for that?
Here goes some example code:
public class FileWriteTest {
public FileWriter file;
public void workingDemo() {
try(FileWriter file = new FileWriter(new File("someFilePath")) {
// do something
} catch (IOException e) {
e.printStackTrace();
}
}
public void notWorkingDemo() {
file = null;
try(file = new FileWriter(new File("someFilePath")) {
// do something
} catch (IOException e) {
e.printStackTrace();
}
}
}
May anyone explain me why there is this convention?

An instance variable may be changed at any point during the execution of the try-with-resources block. This would break its invariant and prevent the cleanup. Note that the local variable is implictly final, for the same reason.
BTW a better question is, why does Java force us to declare a local variable, even if we don't refer to it within the block. C#, for example, doesn't require this.
Update: with version 9, Java has stopped forcing us:
private final Some obj = new Some();
try (obj) {
// obj captured in a hidden local variable, resource closed in the end
}

I suspect the designers considered using a field a bad idea as this allow the object to escape the region of usage. i.e. it is only valid in the try block so you shouldn't be able to access it anywhere else.

Section 14.20.3 of the Java Language Specification states it will only work with local variables.
Why is this? My guess is checking for definite assignment and escapage (the local variable doesn't escape into the scope of another method). A field may be initialized anywhere in the class. My guess is that by validating it's a local variable, it's much simpler to analyse.

With Java 9, They added support for try with resources with variables.
// Original try-with-resources statement from JDK 7 or 8
try (Resource r1 = resource1;
Resource r2 = resource2) {
// Use of resource1 and resource 2 through r1 and r2.
}
// New and improved try-with-resources statement in JDK 9
try (resource1;
resource2) {
// Use of resource1 and resource 2.
}
https://blogs.oracle.com/darcy/more-concise-try-with-resources-statements-in-jdk-9

First off, I think it would be bad practice to have a variable/resource which is used at multiple places. If it is not opened in the try, then you cannot close it afterwards, if it is opened there, then you won't need a non-local variable.
This leads to "second": If you have a resource open already, then you need to close it somewhere else explicitly, otherwise the autoclose wouldn't know if it is open or not.
So, IMHO it makes only sense to handle it the way it is specified in the specification.

From Java 9, no need to use a local variable in try-with-resources block. See here.

It may have to do with consistency with the language specifications.
Whenever a variable is declared between two brackets, it is encapsulated inside and cannot be accessed from the outside:
anything
{
int var;
}
// cannot access var from here!
Why shoul try { } be an exception ?

Related

Java socket, create own universal method // vicious circle

Can you please help me with the answer, please?
I've read a lot, but can understand, how to organize the code.
I want to create my own method to work with the Network and call it time to time in a program.
But this compilation error makes me mad:
variable might be not have been initialized
I do understand why, but I can`t see solution((
My vision is to open Socket and related streams only one time and close it when needed.
public static void socket_r (String action, String ip_addr, String to_write, int port) throws IOException {
String s;
switch (action) {
case "Create": Socket socket = new Socket (ip_addr, port);
OutputStream out_from_socket = socket.getOutputStream();
PrintWriter writer_socket = new PrintWriter(out_from_socket, true);
InputStream input_socket = socket.getInputStream();
BufferedReader reader_socket = new BufferedReader(new InputStreamReader(input_socket));
break;
case "Write": writer_socket.println(to_write);
writer_socket.println();
break;
case "Read": while ((s = reader_socket.readLine()) != null) System.out.println(s);
break;
case "Close": writer_socket.println(to_write);
writer_socket.println();
writer_socket.close();
reader_socket.close();
break;
}
}
Lets start with why the code won't compile ...
The variables reader_socket and writer_socket are local variables. That means:
they must be definitely assigned before you can use them, and
they disappear ... along with their respective values ... when your socket_r method returns to the caller.
In your code, there are lots of places where reader_socket and writer_socket are used without being definitely assigned. For example:
writer_socket.println(to_write);
A call to socket_r can reach that statement without passing through any statement that assigns a value to writer_socket. (Yes. Look at it.)
But here's the problem. Your design requires that a socket_r("write", ...) call uses state that only gets initialized in a socket_r("create", ...) call. And then it gets thrown away.
Basically, you cannot implement that design using local variables for the state.
So what is the solution?
In order of "goodness"
Make the variables static variables in the enclosing class. (This is a bad solution, but it involves the least change to your existing code. Why it is bad is ... well ... read some more about OO and why static should be rarely used.)
Make the method non-static method and make the variables instance variables.
Solution 2 AND replace socket_r with a separate method for each "action".
Solution 3 AND put in some extra logic to enforce a proper "life-cycle" for the socket; i.e. create before reads and writes, no reads or writes after close, etcetera.
Basically, you need to rethink your design to do things in an OO way, and it will get a whole lot easier.

Freemarker ignore missing variables

I'm using freemarker to generate files and I'm struggling with the templateExeptionHandler part. I have variables in my template that don't have to be replaced (if they are not present in the data-model). I don't like to put these variables inside my data-model with the same value (can't get it to work either) and I know I can 'escape' variables in the template itself but I don't really like that solution.
MyTemplateExceptionHandler looks as follows:
class MyTemplateExceptionHandler implements TemplateExceptionHandler {
public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException {
try {
out.write("${" + te.getBlamedExpressionString() + "}");
} catch (IOException e) {
throw new TemplateException("Failed to print error message. Cause: " + e, env);
}
}
}
The problem is that once I'm parsing variables in the form of:
${workflow.input.myVariable}
the result in my new generated file is showing only the first part of this variable:
${workflow}
Any thoughts on how I can get the full variable back and returned in my generated file?
That use case is not supported, as of 2.3.27 at least. It's not even clear how it should work, like, what if the missing variable is a parameter to a directive? Certainly it could be solved for the case of ${} only (even then, only when it appears outside a string literal), but I'm not sure if that addresses the need, or it just lures uses into using it and then they hit a wall later on with a directive parameter... (Or, another tricky case, what's with ${thisIsMissing + thisExists}? I guess it should become to something like ${thisIsMissing + 123}... so doing this right can complicate the core quite much.)

Talend and core java

Hi i am using talend here with java. stuck at a situation.
String modCode <br>
for (productsline product: ProdUtil.getProdForProfile(attrs.dhdeProd.profileId))
{
modCode = product.productCode;
System.out.println("products are:" +modCode);
}
this piece of code prints 3 didd modcodes. which is expected. Now i need to use these modcodes in if components.
M unable to do as it says
local variable modcode may not have been initialised in if component.
How can i do it??
Its all about SCOPE.
You need to move the modCode declaration outside of the if block.
Read here the JLS#14 specs on Blocks and Statements
I'm assuming the if block you want to include it in occurs either in or after the for loop. If the warning about initialization is in your IDE, you may want to explicitly set
String modCode = null;
or
String modCode = "";
Your for loop might not execute if the iterator has no entries. This is why you are getting the warning.

New/strange Java "try()" syntax?

While messing around with the custom formatting options in Eclipse, in one of the sample pieces of code, I saw code as follows:
/**
* 'try-with-resources'
*/
class Example {
void foo() {
try (FileReader reader1 = new FileReader("file1"); FileReader reader2 = new FileReader("file2")) {
}
}
}
I've never seen try used like this and I've been coding in Java for 9 years! Does any one know why you would do this? What is a possible use-case / benefit of doing this?
An other pieces of code I saw, I thought was a very useful shorthand so I'm sharing it here as well, it's pretty obvious what it does:
/**
* 'multi-catch'
*/
class Example {
void foo() {
try {
} catch (IllegalArgumentException | NullPointerException | ClassCastException e) {
e.printStackTrace();
}
}
}
It was added in Java 7. It's called the try-with-resources statement.
/edit
Might as well throw this in here too. You can use the try-with-resources statement to manage Locks if you use a wrapper class like this:
public class CloseableLock implements Closeable {
private final Lock lock;
private CloseableLock(Lock l) {
lock = l;
}
public void close() {
lock.unlock();
}
public static CloseableLock lock(Lock l) {
l.lock();
return new CloseableLock(l);
}
}
try(CloseableLock l = CloseableLock.lock(lock)) { // acquire the lock
// do something
} // release the lock
However, since you have to declare a variable for every resource, the advantage of this is debatable.
This is Java 7's new try-with-resources statement: http://download.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
Those are changes introduced in JDK7.
First statement is a try-with-resources. I don't know exactly why they exist but exceptions are often caused by inputstreams etc, I guess it just improves readability. Edit: thanks to the other answerers, I read the javadoc and I now know that it will close all i/o streams that implement AutoCloseable, omitting the need for a finally block in a lot of situations
Second is a multi-catch, which is really handy when you have different exceptions that you handle in exactly the same way.
Same usage as using(Resource) in C Sharp,which means this resource will be automatic recycled when your program has leaven out of this code block.(Just my opinion)
The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource
The try-with-resources Statement
It's called try-with-resource. It's a way so as to not have to clean after yourself as the language will do it for you.
it was added in java 7. It is called try with resources. Try with resources statement feature was introduced in java 7 version. Try with resource statement is a try statement that declares one or more statements. A resource is an object that must be closed after the program is finished with it.
Before java 7 we use finally block to close the resources that we have used in our program. In finally block we have to close all the resources manually that we have used in our program.
For more information you can visit try with resources
That is called with a try with resources. in a try with resources, any kind of closable stream declared in the resources section will be closed after the try statement is done. So it pretty much is a
try{
InputStream is;
//Stuff
}finally{
is.close()
}
The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

Replace New with other solution?

This code has lot of trouble for my AIR 2.0 Native process which I tried to launch Java from AIR application, then the Java.exe terminate itself in the Windows Task manager, I found that new MidiTest() was the caused. Is there a better solution for new instance?
public static void main(String[] arg) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (!(speed.equals(speed_stop))) {
try {
speed = in.readLine();
if(!(Global.newPlayer.equals("1"))){new MidiTest();}
} catch (IOException e) {
System.err.println("Exception while reading the input. " + e);
}
}
}
private MidiPlayer player;
public MidiTest() {
System.out.println("Start player");
// /*
}
There is no alternative to new.
This is the only way to instantiate an object. Even if you use reflection, you're still calling the constructor. You need to track down the problem. Find the exact exception that's being caused, and the exact line number, and then see what you need to do to fix that problem.
I can see that you didn't provide a complete copy of your code. There's an open comment before the close brace, and it's not right. So that means we can't help you any further with the information we have.
No, the only other option for creating a new instance of your class would be using reflection, which is a much more obscure and error prone choice than new. It should not be used unless one really needs to. And even that is loading the class and calling the object's constructor in the end, exactly the same way as new.
I suspect the problem lies somewhere in code you haven't shown to us. Does MidiTest have any (static or nonstatic) initializer blocks? Is that println() statement really the only code in its constructor?
Of course, it helped if you traced down what is the exact error/exception causing the termination and where exactly does it originate from :-)

Categories

Resources