java异常看这篇就够了http://www.cnblogs.com/lulipro/p/7504267.html
1.类路径
所谓的类路径就是指程序运行时jvm要加载的类的.class文件所在地方
注意两种情况:当我们是在一个完整项目下写代码的时候,类路径一般IDE都会帮我们设置好,一般都是在xx/classes或者xx/lib这样的地方,项目打包的时候,这些会被打包进去。还有一种情况,就是我们可能只是单纯的使用简单的编辑器想验证一下某个简单的想法的时候,这时候我们没有用IDE,简单的编写个java文件,然后javac,java命令运行一下就能执行,一般这样的都是实现简单的功能,需要用到的类都是java语言本身的类,所以我们在使用import语句导入所需的类的时候,运行的时候,当看到import的语句,就去环境变量classpath指定的路径下找需要的.class文件,如果没找到就会报错
2.JAR(java archive)java归档文件
使用了Zip压缩格式,里面可以放各种资源文件,每个jar文件都有个清单文件(manifest),名字为MAINFEST.MF,用来对jar文件的内容和来源进行说明,放在一个META-INF的目录里,清单文件每个条目用空行隔开,清单文件必须以换行符结尾
jdk的java内置类的.class文件在一个jre/lib/rt.jar的文件里
3.可运行的jar
在清单文件中指定Main-Class
java.exe用于启动window console 控制台程序
javaw.exe用于启动 GUI程序
javaws.exe用于web程序。
jvm.dll就是java虚拟机规范在windows平台上的一种实现
5.资源文件
类加载器可以在类路径下找到需要加载的.class文件,资源文件怎么办呢,Class有两个方法
URL getResource(String name)
InputStream getResourceAsStream(String name),没找到则返回null,不会抛异常或发生I/O错误
资源的路径默认都是相对于需要加载的类的.class文件所在的目录
6.密封
想要让一个包不让别的类放进来,可以使用密封机制。使用密封机制,需要把这个包打包成jar包,并在jar包的清单文件中加入Sealed:true,可以全局设置,也可以单独对每个条目
7.属性映射Properties
Properties类:存储键值对
Properties settings = new Properties()
也可以在构造的时候提供一个二级表存放默认值,如Properties settings = new Properties(default)
settings.put("name","luckee")//添加属性
settings.put("address","china")//添加属性
FileOutputStream out = new FileOutputStream("program.properties")
settings.store(out,"this is header")//写进文件,第二个参数存储文件的第一行标题
---------------------------------分割线--------------------------------------
FileInputStream in = new FileInputStream("program.properties")
Properties settings = new Properties()
settings.load(in);//读取文件
String name = settings.getProperty("name")//获取属性
也可以指定默认值String name = settings.getProperty("name","jack"),如果没有name属性,则取默认值
String address = settings.getProperty("address")
8.java.lang.System
Properties getProperties()//获取全部系统属性
String getProperty(String key)//获取给定键名的系统属性
user.home属性是系统当前用户的主目录
9.首选项Preference
中心知识库,以树的形式(类似于包结构),为每个节点维护(属性,设置等数据),建议跟包结构一致,两种根节点,系统根节点和当前用户根节点,下面是Preference的API
Preference userRoot()
Preference systemRoot()
preference node(String path)
Preference userNodeForPackage(Class c1)
Preference systemNodeForPackage(Class c1)
String[] keys()
String get(String key,String default)
int getInt(String key,int default)//其他类型的类似
String put(String key,String value)
int putInt(String key,int value)//其他类型的类似
exportSubtree(OutputStream out)
exportNode(OutputStream out)
importPreferences(InputStream in)
10.Throwable是一个类,不是接口
Throwable派生出Error(系统的内部错误和资源耗尽错误,不应该抛出)和Exception,Exception派生出RuntimeException(程序本身的错误,如错误的类型转换,数组越界,空指针等)和其他的非程序本身的错误引起的异常(如IOEXception,如试图打开一个不存在的文件,根据名称加载一个不存在的类等),Error和RuntimeException派生出来的称为未检查(unchecked)异常,其他的派生出来的称作已检查(checked)异常,编译器将检查是否为所有的checked异常提供了异常处理器
在处理异常的时候,可以选择抛出,也可以选择捕获。对于知道如何处理的异常就捕获,不知道如何处理的就向上抛出(给调用者)。对于选择抛出的,必须在方法声明的时候用throws进行声明,声明多个异常用逗号分隔。调用者在调用这种方法的时候,必须进行处理,或者选择继续向上传递(抛出)。对于子类覆盖父类方法的时候,对于已检查异常,如果父类方法使用了throws,那么子类throws的异常通用性不能大于父类(即可以是同一异常,子类异常或者不抛出异常)
通常我们的思路可以是,在方法定义时声明可能会抛出异常,方法内并不捕获异常,而让方法的调用者自己去处理异常,如果一个方法内抛出了一个异常(new一个然后抛出),那方法就会停止运行,将异常抛给调用者,不用去担心返回值了。如果是捕获了一个异常,那就停止执行try代码块里面的代码,转去执行catch块和finally块的代码,然后接着执行try代码块外面的代码,如果catch里面又抛出了异常,那就直接将异常抛给方法的调用者,try代码块外面的代码也不执行了,方法结束
catch代码块中也是可以继续抛出异常的,通常这样做可以改变异常的类型,可以将捕获的异常进行包装,并将其设置为包装后的异常的原因,这样就不会丢失原始异常的信息
当捕获多个异常的时候,应该将具体的异常放在前面,通用的放在后面(如子类放在前,父类放在后)
如果有异常出现,没有捕获,那方法将停止运行
finally块中的return会覆盖try块中的return,如果finally块中也抛出异常,那么会覆盖原始的异常,原始的异常会丢失(卷一p484~485)
public static void main(String[] args) {
System.out.println(f());//4
}
public static int f(){
try{return 2;}
finally{return 4;}
}
catch (Exception e)中的e为final,不可以再进行赋值
带资源的try(try-with-resources)
try(declare resource here……){……},try语句块结束时,资源会自动关闭(卷一p486~487)
11.堆栈追踪stackTrace(卷一p487)Thread.dumpStack()(卷一p514)
12.异常机制使用的6个技巧(原则,卷一p490)
不要用异常代替简单错误检查,捕获异常所花的时间更多
不要分过细化异常,这样会使代码更多。应该在一段代码后统一使用catch语句
异常要分层次,用最适合的异常类型,不要笼统使用Throwable,Exception,RuntimeException
不要压制异常
检错错误时,要更苛刻。比如,对于无效的参数宁可抛出异常,也不要返回一个异常的值
不要羞于传递异常。有时候把异常交给调用者去处理
13.断言机制,关键字assert
测试代码不应该存在于最终的代码中,断言机制就是解决这个问题(断言默认关闭)
不管是测试代码还是断言机制,都是在开发和测试阶段使用的
14.日志(Logger)
日志分为七个级别,从高到低为以下
SERVER
WARNING
INFO
CONFIG
FINE
FINER
FINEST
默认级别是INFO(即记录INFO及以上的日志)
全局日志记录器Logger.global
Logger.getGlobal()//获取全局记录器
Logger.getLogger("xxx.xxx.xxx")//根据包名来获得记录器,子记录器会继承父记录器的级别
logger.setLevel(Level.CONFIG)//设置记录器级别为CONFIG,Level.ALL开启所有级别的记录,Level.OFF关闭所有级别的记录
logger.info(message)//以info级别记录message
logger.warning(message)//以warning级别记录message
logger.log(Level.info,message)//以info级别记录message
默认的日志配置文件为jre/lib/logging.properties
关于日志(java.util.logging),有4个器:记录器,处理器,过滤器,格式化器
日志工具log4j
单元测试Junit
压力测试Jmeter
jdk自带性能分析工具jconsole,jmap(将堆中的对象转存为一个文件),jhat(开启一个http服务,使得可以通过浏览器来进行查看转存到的堆文件)
要观察类的加载过程,可以启动虚拟机的时候加上-verbose选项
javac -Xlint告诉编译器对一些普片出现的代码问题进行检查
如javac -Xlint:fallthrough当switch缺少break语句的时候编译器会给出报告
java -X
注意-1
运行时异常是RuntimeException类及其子类的异常,是非受检异常,如NullPointerException、IndexOutOfBoundsException等。由于这类异常要么是系统异常,无法处理,如网络问题;要么是程序逻辑错误,如空指针异常;JVM必须停止运行以改正这种错误,所以运行时异常可以不进行处理(当然也可以处理,捕获或向上抛出),而由JVM自行处理。Java Runtime会自动catch到程序throw的RuntimeException,然后停止线程,打印异常。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类,是受检异常。非运行时异常必须进行处理(捕获或向上抛出),如果不处理,程序将出现编译错误。一般情况下,API中写了throws的Exception都不是RuntimeException
unchecked异常
checked异常
注意-2
try{
......//1,可能抛出异常的语句
......//2,异常后面的语句
} catch(Exception e) {
......//3,处理异常语句
}
finally{
......//4,finally语句
}
......//5,try块后的语句
如果没有异常发生,将执行1,2,4,5
如果异常发生被捕捉了只是单纯处理并未往上抛出,执行1,3,4,5
如果异常发生被捕捉了并向上抛出,则执行1,3,4
也就是说发生了异常,捕获并处理了的话,方法会继续运行;如果没有捕获或者捕获了但又重新抛出(throw)了异常,方法则会停止运行
如果想要在处理完异常后,接着执行try语句块中抛出异常位置后面的代码,可以将try语句放入一个循环中(https://blog.csdn.net/yangyong0717/article/details/78493074)