异常 Logger
推荐博客 http://blog.csdn.net/hguisu/article/details/6155636
异常分类
所有的异常有Throwable(直接继承了Object)继承而来,有两个子类Error和Exception
- Error , 描述了java运行时系统的内部错误和资源耗尽错误,应用程序不应该抛出这种类型的错误,当出现了这种错误,我们只能告诉使用者错误类型,安全的终止程序,没办法修复程序
- Exception层次的错误是我们需要关注的,Exception可以分为两个分支,一个是RuntimeException,由程序错误导致的异常是RuntimeException异常,是运行时异常(在运行时才可以发现的异常);另外一个是其他异常(IoException是其中的一个代表),编译时异常(编译时可以发现的异常)
Runtime异常:
错误的类型转换
数组访问越界
访问空指针
其他异常:
试图在文件尾部读取数据
试图打开一个不存在的文件
Error类和RuntimeException类的所以异常称为未检查异常,程序没有强制我们去处理这部分异常,其他的异常称为已检查异常,我们做了相应的处理。
自定义异常
#自定义异常只要类继承了Exception或者子类就可以
#包含两个构造器,一个是默认的构造器,另一个是有打印信息的构造器
public class PrivateException extends Exception {
public PrivateException() {
}
public PrivateException(String message) {
super(message);
}
}
#使用
public static void main(String[] args) {
for(int i = 0; i < 10;i++){
if(i == 5){
try {
//代码1 throw new PrivateException();
//代码2 throw new PrivateException("I am here error");
} catch (PrivateException e) {
e.printStackTrace();
}
}
}
}
#代码1结果
#demo.Crazy.four.PrivateException
#at demo.Crazy.four.Test.main(Test.java:11)
#代码2结果,代码2打印出了我们声明的错误信息 I am here error
#demo.Crazy.four.PrivateException: I am here error
#at demo.Crazy.four.Test.main(Test.java:11)
异常的处理
异常的处理有两种,一种是使用try catch语句捕获异常进行处理,另一种是使用throws抛出异常,给方法的调用者处理。通常情况下,知道如何处理的异常直接捕获处理,不知道如何处理的异常要进行异常传递。
1.多个catch块的情况
多个catch块的情况, try 语句后面添加任意数量的 catch 块。如果保护代码中发生异常,异常被抛给第一个 catch 块。如果抛出异常的数据类型与第一个catch块匹配,它在这里就会被捕获。如果不匹配,它会被传递给第二个 catch 块。如此,直到异常被捕获或者通过所有的 catch块
2.finally关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally代码块中的代码总会被执行。
3.try中有return时
try{} 里有一个 return 语句,那么紧跟在这个 try 后的 finally{} 里的 code 会不会被执行,什么时候被执行,在 return 前还是后?
会执行,在方法返回调用者前执行
在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值。显然,在finally中返回或者修改返回值会对程序造成很大的困扰,C#中直接用编译错误的方式来阻止程序员干这种龌龊的事情,Java中也可以通过提升编译器的语法检查级别来产生警告或错误,Eclipse中可以在如图所示的地方进行设置,强烈建议将此项设置为编译错误。
异常处理技巧
- 避免过大的try块,这样出错时不容易定位到错误
- 细化异常的类型,不要不管什么异常都写成Exception,这样虽然代码可简单
- catch块尽量捕获一类异常,当你选择了捕获异常就应该对它负责,不要只是打印异常,否则就直接抛出异常
- 不要把自己能处理的异常抛出去
- 不要使用try…catch参与流程控制
- 在多个catch时在最后加上catch(Exception),避免遗漏异常
Logger机制
在刚开始写程序的时候会用到好多System.out.println()来得到信息判断代码错误情况,在编码结束后会发现好多的打印无用信息,删除起来又比较麻烦。我们也可以自定义Logutils打印类,通过一个boolean类型的参数来控制调试期打印,发布程序不打印,下面简单写了一个
public class LogUtils {
private LogUtils(){throw new AssertionError();}
//是否打印flag
private static boolean isPrint = true;
//log打印语句
public static void log(String TAG , String msg){
if(isPrint){
System.out.println(TAG +": "+msg);
}
}
//关闭log打印
public static void closeLog(){
if(isPrint == true){
isPrint = false;
}
}
//开启log打印
public static void openLog(){
if(isPrint == false){
isPrint = true;
}
}
}
Java本身自带了Logger类来解决上述问题
#Logger简单使用,下面全部使用了全局打印logger
public class Test {
public static void main(String[] args) {
// Logger.getGlobal().setLevel(Level.OFF); //在程序开始可以关闭所有打印语句,在发布期使用
// Logger.getGlobal().log(Level.FINE,"Open the menu"); //log第一个参数指定了打印级别
Logger.getGlobal().info("error"); //info()打印级别就是INFO级别
System.out.println("process exit ");
}
}
Logger有下面7个日志级别,就和linux内核中的printk,android中的Log一样,一般每个级别代码打印信息的严重性不同,默认打印INFO及其以上的信息,可以在${jre}/lib/logging.properties中更改默认配置
- SERVER 最高的
- WARNING
- INFO
- CONFIG
- FINE
- FINER
- FINEST
下面是网上一个博主分析的代码,存储到本地文件
http://blog.csdn.net/nash603/article/details/6749914
#输入文件到本地日志文件
public class LoggerUtil {
/** 存放的文件夹 **/
private static String file_name = "邮政储蓄日志";
/**
* 得到要记录的日志的路径及文件名称
* @return
*/
private static String getLogName() {
StringBuffer logPath = new StringBuffer();
logPath.append(System.getProperty("user.home"));
logPath.append("\\"+file_name);
File file = new File(logPath.toString());
if (!file.exists())
file.mkdir();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
logPath.append("\\"+sdf.format(new Date())+".log");
return logPath.toString();
}
/**
* 配置Logger对象输出日志文件路径
* @param logger
* @throws SecurityException
* @throws IOException
*/
public static void setLogingProperties(Logger logger) throws SecurityException, IOException {
setLogingProperties(logger,Level.ALL);
}
/**
* 配置Logger对象输出日志文件路径
* @param logger
* @param level 在日志文件中输出level级别以上的信息
* @throws SecurityException
* @throws IOException
*/
public static void setLogingProperties(Logger logger,Level level) {
FileHandler fh;
try {
String str = getLogName();
System.out.println(str);
fh = new FileHandler(str,true);
logger.addHandler(fh);//日志输出文件
//logger.setLevel(level);
fh.setFormatter(new SimpleFormatter());//输出格式
//logger.addHandler(new ConsoleHandler());//输出到控制台
} catch (SecurityException e) {
logger.log(Level.SEVERE, "安全性错误", e);
} catch (IOException e) {
logger.log(Level.SEVERE,"读取文件日志错误", e);
}
}
public static void main(String [] args) {
Logger logger = Logger.getLogger("sgg");
try {
LoggerUtil.setLogingProperties(logger);
logger.log(Level.INFO, "ddddd");
logger.log(Level.INFO, "eeeeee");
logger.log(Level.INFO, "ffffff");
logger.log(Level.INFO, "gggggg");
logger.log(Level.INFO, "hhhhhh");
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}