第12章 通过异常处理错误
0、异常层次结构:
Throwable---Error(Java运行时系统的内部错误和资源耗尽错误,无需考虑)
---Exception---RuntimeException(程序错误导致的异常)---以上两类并不需要程序员进行处理
---其他
1、异常链示例代码
//: exceptions/DynamicFields.java
// A Class that dynamically adds fields to itself.
// Demonstrates exception chaining.
class DynamicFieldsException extends Exception {}
public class DynamicFields {
private Object[][] fields;
public DynamicFields(int initialSize) {
fields = new Object[initialSize][2];
for (int i = 0; i < initialSize; i++)
fields[i] = new Object[]{null, null};
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (Object[] obj : fields) {
result.append(obj[0]);
result.append(": ");
result.append(obj[1]);
result.append("\n");
}
return result.toString();
}
private int hasFields(String id) {
for (int i = 0; i < fields.length; i++)
if (id.equals(fields[i][0]))
return i;
return -1;
}
private int getFieldNumber(String id) throws NoSuchFieldException {
int fieldNum = hasFields(id);
if (fieldNum == -1)
throw new NoSuchFieldException();
return fieldNum;
}
private int makeField(String id) {
for (int i = 0; i < fields.length; i++)
if (fields[i][0] == null) {
fields[i][0] = id;
return i;
}
Object[][] tmp = new Object[fields.length + 1][2];
for (int i = 0; i < fields.length; i++)
tmp[i] = fields[i];
for (int i = fields.length; i < tmp.length; i++)
tmp[i] = new Object[]{null, null};
fields = tmp;
return makeField(id);
}
public Object getField(String id) throws NoSuchFieldException {
return fields[getFieldNumber(id)][1];
}
public Object setField(String id, Object value) throws DynamicFieldsException {
if (value == null) {
DynamicFieldsException dfe = new DynamicFieldsException();
dfe.initCause(new NullPointerException());
throw dfe;
}
int fieldNumber = hasFields(id);
if (fieldNumber == -1)
fieldNumber = makeField(id);
Object result = null;
try {
result = getField(id);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
fields[fieldNumber][1] = value;
return result;
}
public static void main(String[] args) {
DynamicFields df = new DynamicFields(3);
System.out.println(df);
try{
df.setField("d", "A value for d");
df.setField("number", "47");
df.setField("number2", "48");
System.out.println(df);
df.setField("d", "A new value for d");
df.setField("number3", 11);
System.out.println("df: " + df);
System.out.println("df.getField(\"d\"): " + df.getField("d"));
Object field = df.setField("d", null);
}
catch (NoSuchFieldException e){
e.printStackTrace(System.out);
}
catch(DynamicFieldsException e){
e.printStackTrace(System.out);
}
}
} /* Output:
null: null
null: null
null: null
d: A value for d
number: 47
number2: 48
df: d: A new value for d
number: 47
number2: 48
number3: 11
df.getField("d"): A new value for d
DynamicFieldsException
at DynamicFields.setField(DynamicFields.java:59)
at DynamicFields.main(DynamicFields.java:88)
Caused by: java.lang.NullPointerException
at DynamicFields.setField(DynamicFields.java:60)
... 1 more
*///:~
2、finally 语句块:https://www.ibm.com/developerworks/cn/java/j-lo-finally/index.html
- 只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行。
- 当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。
- 程序首先执行try语句,如果不存在异常将跳过控制转移语句(return,continue,break,throw)而直接执行finally语句,执行完finally语句再返回执行try中的控制转移语句;但如果存在异常,将转入对应的catch语句(之后的try语句将被忽略),之后同样在控制转移语句前执行finally语句,并最终返回执行catch中的控制转移语句。不过,如果finally中存在控制转移语句,将直接跳转而不执行try或者catch中的控制转移语句。
- 但在跳转到finally语句执行之前,程序会将try或catch中的变量入栈保存,待finally语句执行完之后,将入栈数据重新加载,因此并不能通过finally语句来实现对try或catch语句中的返回值进行修改。
3、子类的异常相比于基类只能更加具体,而如果基类没有异常,那么子类将不允许抛出异常。
4、对于可能存在异常的方法,要么通过catch捕获异常(也可以经过处理之后再抛出另一个异常)或者在方法声明时通过throws声明该方法可能抛出的异常。
5、但try语句中存在打开的资源(文件,数据库)需要关闭时,相比于通过finally语句进行处理,使用带资源的try语句(try(Resource res=...))通常更好。这样能够保证这类资源在出现异常时能够被正确的关闭。
6、日志处理
- 创建日志
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
- 记录日志时间
logger.warning("This is a warning!");
logger.setLevel(Level.WARNING);
- 日志实例
import java.util.logging.Logger;
public class LoggerTest {
public static void main(String[] args) {
Logger logger = Logger.getLogger(LoggerTest.class.getName());
logger.finest("this is finest");
logger.finer("this is finer");
logger.fine("this is fine");
logger.config("this is config");
logger.info("this is info");
logger.warning("this is a warning");
logger.severe("this is severe");
}
}