Does everything after the try statement have to be included in this try statement to access the variables inside it?

I am learning Java, and one thing I found that I don't like, usually when I have code like this:

import java.util.*; import java.io.*; public class GraphProblem { public static void main(String[] args) { if (args.length < 2) { System.out.println("Error: Please specify a graph file!"); return; } FileReader in = new FileReader(args[1]); Scanner input = new Scanner(in); int size = input.nextInt(); WeightedGraph graph = new WeightedGraph(size); for(int i = 0; i < size; i++) { graph.setLabel(i,Character.toString((char)('A' + i))); } for(int i = 0; i < size; i++) { for(int j = 0; j < size; j++) { graph.addEdge(i, j, input.nextInt()); } } // .. lots more code } } 

I have an uncaught exception around my FileReader.

So, I have to wrap it in a try-catch in order to catch this particular exception. My question is, should try { } cover everything after that in my method, which wants to use either my FileReader (in) or my scanner (input)?

If I don’t transfer the rest of the program to this try statement, then something outside of it cannot access in / input, because it may not be initialized or initialized outside its scope. Therefore, I cannot isolate try-catch to just say the part that initializes the FileReader and closes the try statement immediately.

So, is it a “best practice” to force the try statement to wrap all parts of the code that will access the variables initialized in it?

Thanks!

+6
java exception exception-handling
source share
7 answers

If you prefer not to wrap code after the FileReader constructor, you can declare FileReader outside of the try / catch block, for example:

 FileReader fr = null; try { fr = new FileReader(args[1]); } catch (IOException e) { // handle } // code that uses fr 

This is a reasonable design, and I use it often. Make sure that in the following code you are correctly handling the possibility that fr is null (i.e., the Constructor throws an exception).

+9
source share

This is not a problem with try / catch blocks per se. The problem is related to changing the variables and that you should have a try / catch block due to a checked exception and therefore create a new scope.

You also have another option - declare the thrown exception (s) as throws from your method.

 public static void main(String[] args) throws IOException { // ...code here... } 

This is completely legal for the main method.

If you want to handle the exception, as in a larger program. You can define a specific try / catch around the problematic block of code and use a variable outside the scope by declaring a variable outside this scope, as many have answered:

 FileReader fr = null; // must be initialized here if the exception handling code // does not exit the method try { fr = new FileReader(fileName); } catch (IOException ex) { // log, print, and/or return // if you return or exit here then subsequent code can assume that fr is valid } 

You can also move the code to another method that deals with the exception:

 private static FileReader openReader(String fileName) { try { return new FileReader(fileName); } catch (IOException ex) { // log/print exception return null; // caller must then expect a null // or throw new RuntimeException(...); // throw a RuntimeException of some kind (may not be good practice either) } } 

You can also move the file processing code to another method. This can be better and allow you to more correctly follow the open / closed in the final idiom:

 FileReader fr = null; try { fr = new FileReader(fileName); Scanner input = new Scanner(fr); processInput(input); } catch (IOException ex) { // log/print exception } finally { if (fr != null) { try { fr.close(); } catch (IOException ex) { // empty } } } private static void processInput(Scanner in) throws IOException { // ...processing here } 

In the next part, you can use a third-party library (Apache File Utils) or write a simple method to provide a static safe closing method that does not throw exceptions.

You really should take a look at breaking up large methods into smaller units, and this will often give you a clearer way of handling exceptions.

+3
source share

Not. You can declare it as follows:

 FileReader in = null; Scanner input = null; try { in = new FileReader(args[1]); input = new Scanner(in); } catch(IOException ioe) { // } 
+2
source share

Yes and no. Try initiating its own local region, so when you do this:

 try { FileReader reader = new FileReader(args[1]); // Stuff } catch(Exception e) { } 

The reader variable is visible only within the limits of the try {} block. This is the preferred behavior. If you want to use it outside (in the case of the i / o file it is not recommended) you need to declare it outside of try / catch. A good example would be a flag:

 boolean isValidFile = false; try { FileReader reader = new FileReader(args[1]); // Do Stuff isValidFile = true; } catch(Exception e) { // Handle Errors } System.out.print("Valid File: "); System.out.println(isValidFile); 
0
source share

If you are just learning, you can force your method to throw an exception. However, this is a great way to handle exceptions, if you are just learning, you probably want to focus more on the logic of what your code does. Once you are comfortable, you can properly examine exceptions to handle.

So, your code should look like this: you don't have to worry about try / catch statements:

 public class GraphProblem { public static void main(String[] args) throws Exception { //your code } } 

Again, this is not the best practice, but it allows you to focus on your business logic rather than error handling. Once you master the business logic, you will be able to understand the exception handling, which is a topic for yourself.

0
source share

Local variables declared in a block scoped to this block.

So, is it a “best practice” to force the try statement to wrap all parts of the code that will access the variables initialized in it?

In general, you should try to minimize the amount of your variables in order to make them as narrow as possible. This is described in Effective Java and Code Complete , among others.

This type of code is a recipe for NullPointerExceptions :

 FileReader in = null; try { in = new FileReader(filename); } catch(IOException e) { //handle error, but now what? } // Code that needs "in", but what if it is null // because of a FileNotFoundException? // This code is junk. 

Almost all local variable declarations should include assignment.

 FileReader in = new FileReader(filename); 

If you follow this rule of thumb, you will get the best code.


 // .. lots more code 

If you have gigantic try / catch statements, it sounds like your methods are too big. This is a code organization problem, not something special with try / catch.

  public static void main(String[] args) { if (args.length < 1) { System.out.println("Error: Please specify a graph file!"); return; } try { processGraphFile(args[0]); } catch (IOException e) { // Deal with error } } private static void processGraphFile(String filename) throws IOException { FileReader in = new FileReader(filename); try { Scanner scanner = new Scanner(in); processGraph(scanner); if (scanner.ioException() != null) { throw scanner.ioException(); } } finally { in.close(); } } //other methods 

Aside:

  • Note that Java arrays start at index 0 , not 1
  • FileReader convenient during training, but, as a rule, it should be avoided due to encoding problems; this is unlikely to be a problem until the code leaves your machine.
0
source share

You must definitely follow the pattern above. If I remember my research on SCJP correctly, the compiler does not try to optimize everything that is in the try block, so you should try to catch at the lowest level.

-2
source share

All Articles