我正在学习java,有一件事我发现我不喜欢,通常是我有这样的代码:
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
}
}
我的FileReader周围有一个未捕获的异常。
所以,我必须将它包装在try-catch中以捕获该特定异常。我的问题是try { }
必须包含我想要使用我的FileReader(in)或我的Scanner(输入)的方法之后的所有内容吗?
如果我没有将该程序的其余部分包装在该try语句中,那么它之外的任何内容都无法访问in / input,因为它可能尚未初始化或已在其范围之外初始化。因此,我无法将try-catch隔离出来,只是说出初始化FileReader的部分,然后立即关闭try语句。
那么,让try语句包含将要访问其中初始化变量的代码的所有部分是“最佳实践”吗?
谢谢!
答案 0 :(得分:9)
如果您对FileLader构造函数之后的不包装代码感到满意,则可以在try / catch块之外声明FileReader,如下所示:
FileReader fr = null;
try
{
fr = new FileReader(args[1]);
}
catch (IOException e)
{
// handle
}
// code that uses fr
这是一个合理的设计,我经常使用它。请确保在以下代码中正确处理fr
为空的可能性(即构造函数引发异常)。
答案 1 :(得分:3)
这不是try / catch块的问题。问题是变量作用域,并且由于已检查的异常,您必须具有try / catch块,从而建立新的作用域。
您还有另一种选择 - 从您的方法中将已检查的异常声明为throws
。
public static void main(String[] args) throws IOException {
// ...code here...
}
这对于main
方法来说是完全合法的。
如果你确实想要处理异常,就像你应该在一个更大的程序中一样。您可以围绕代码问题块定义特定的try / catch,并通过在该范围之外声明变量来使用范围之外的变量,因为许多人已经回答:
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
}
您还可以将代码移动到另一个处理异常的方法:
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)
}
}
您还可以将文件处理代码移动到另一个方法。这可能会更好,并允许您更正确地遵循最终成语中的打开/关闭:
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
}
对于close部分,您可以使用第三方库(Apache File Utils)或编写一个简单的方法来提供不会抛出异常的静态安全关闭方法。
你真的应该考虑将大型方法分解成更小的单元,这通常会为你提供更清晰的处理异常的方法。
答案 2 :(得分:2)
没有。您可以这样声明:
FileReader in = null;
Scanner input = null;
try {
in = new FileReader(args[1]);
input = new Scanner(in);
} catch(IOException ioe) {
//
}
答案 3 :(得分:0)
是和否。 Try启动它自己的本地范围,所以当你这样做时:
try
{
FileReader reader = new FileReader(args[1]);
// Stuff
}
catch(Exception e) { }
reader
变量仅在try {}块的约束内可见。这是首选行为。如果你想在外面使用它(在文件i / o的情况下它不被推荐)你需要在try / catch之外声明它。一个恰当的例子是一面旗帜:
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);
答案 4 :(得分:0)
如果您刚学习,可以让您的方法抛出异常。它不是处理异常的好方法,但是如果你只是在学习,你可能希望更多地关注你的代码所做的逻辑。一旦你对此感到满意,那么你可以正确地研究处理异常。
因此,您的代码应如下所示,您不必担心try / catch语句:
public class GraphProblem {
public static void main(String[] args) throws Exception {
//your code
}
}
同样,这不是最佳做法,但它允许您专注于业务逻辑而不是错误处理。一旦您熟悉了业务逻辑,那么您可以深入了解异常处理,这是一个自身的主题。
答案 5 :(得分:0)
那么,让try语句包含将要访问其中初始化变量的代码的所有部分是“最佳实践”吗?
通常,您应该尽量减少变量的范围,以使它们尽可能地缩小。 此问题已在Effective Java和Code Complete等内容中介绍。
此类代码是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.
实际上,所有局部变量声明都应包含赋值。
FileReader in = new FileReader(filename);
如果您遵循此经验法则,您最终会得到更好的代码。
// .. lots more code
如果你有巨大的try / catch语句,听起来你的方法太大了。这是一个代码组织问题,而不是专门针对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
暂且不说:
0
开始,而不是1
FileReader
在学习时很方便,但由于编码问题通常应该避免;在代码离开您的计算机之前,这不太可能成为问题答案 6 :(得分:-2)
你一定要遵循上面的模式。如果我从SCJP学习中记得,编译器不会尝试优化try块中的任何内容,所以你应该尽可能地尝试捕获。