Java 提高(4)----- 异常 Logger

来源:互联网 发布:法国大餐 知乎 编辑:程序博客网 时间:2024/06/17 00:50

异常 Logger


推荐博客 http://blog.csdn.net/hguisu/article/details/6155636

异常分类

此处输入图片的描述
所有的异常有Throwable(直接继承了Object)继承而来,有两个子类Error和Exception

  1. Error , 描述了java运行时系统的内部错误和资源耗尽错误,应用程序不应该抛出这种类型的错误,当出现了这种错误,我们只能告诉使用者错误类型,安全的终止程序,没办法修复程序
  2. 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简单使用,下面全部使用了全局打印loggerpublic 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();        }    }}
原创粉丝点击