空指针异常,该异常出现在我们操作某个对象的属性或方法时,如果该对象是null
时引发。
String str = null;
str.length();//空指针异常
上述代码中引用类型变量str的值为null
,此时不能通过它调用字符串的方法或引用属性,否则就会引发空指针异常。
找到为什么赋值为null
,确保该对象的值不能为null
再操作属性或方法即可。
数字格式异常,该异常通常出现在我们使用包装类将一个字符串解析为对应的基本类型时引发。
String line = "123.123";//小数不能转换为整数!
int d = Integer.parseInt(line);//抛出异常NumberFormatException
System.out.println(d);
上述代码中由于line的字符串内容是"123.123",而这个数字是不能通过包装类Integer
解析为一个整数因此出现该异常。
注意:非数字的字符串在解析时也会出现该异常。
确保解析的字符串正确表达了基本类型可以保存的值
String line = "123";
int d = Integer.parseInt(line);
System.out.println(d);//123
字符串下标越界异常,该异常通常出现在String对应的方法中,当我们指定的下标小于0或者大于等于字符串的长度时会抛出该异常。
String str = "thinking in java";
char c = str.charAt(20);//出现异常
System.out.println(c);
指定下标时的范围应当在>=0并且<=字符串的长度。
无效的类异常,该异常出现在使用java.io.ObjectInputStream
在进行对象反序列化时在readObject()
方法中抛出。这通常是因为反序列化的对象版本号与该对象所属类现有的版本号不一致导致的。
可以通过在类上使用常量:
static final long serialVersionUID = 1L;
来固定版本号,这样序列化的对象就可以进行反序列化了。
JAVA建议我们实现Serializable
接口的类主动定义序列化版本号,若不定义编译器会在编译时根据当前类结构生成版本号,但弊端是只要这个类内容发生了改变,那么再次编译时版本号就会改变,直接的后果就是之前序列化的对象都无法再进行反序列化。
如果自行定义版本号,那么可以在改变类内容的同时不改变版本号,这样一来,反序列化以前的对象时对象输入流会采取兼容模式,即:当前类的属性在反序列化的对象中还存在的则直接还原,不存在的就是用该属性的默认值。
注意:之前没有定义序列化版本号时序列化后的对象都无法再反序列化回来,所以若写入了文件,可将之前的那些文件都删除,避免读取即可。
不能序列化异常,该异常通常出现在我们使用java.io.ObjectOutputStream
进行对象序列化调用writeObject()
方法时。原因时序列化的对象所属的类没有实现java.io.Serializable
接口导致。
将序列化的类实现该接口即可
不支持的字符集异常,该异常通常出现在使用字符串形式指定字符集名字时,由于字符集名字拼写错误导致。例如
PrintWriter pw = new PrintWriter("pw.txt", "UFT-8");
上述代码中,字符集拼写成"UFT-8"就是拼写错误。
常见的字符集名字:
将字符集名字正确拼写即可
文件没有找到异常,该异常通常出现在我们使用文件输入流读取指定路径对应的文件时出现
FileInputStream fis = new FileInputStream("f1os.dat");
上述代码如果指定的文件f1os.dat文件不在当前目录下,就会引发该异常:
java.io.FileNotFoundException: f1os.dat
(系统找不到指定的文件。)
注意:抽象路径"f1os.dat"等同于"./f1os.dat"。因此该路径表示当前目录下应当有一个名为f1os.dat的文件。
还经常出现在文件输出流写出文件时,指定的路径无法将该文件创建出来时出现
FileOutputStream fos = new FileOutputStream("./a/fos.dat");
上述代码中,如果当前目录下没有a目录,那么就无法在该目录下自动创建文件fos.dat,此时也会引发这个异常。
其他API上出现该异常通常也是上述类似的原因导致的。
连接异常,连接被拒绝了,这通常是客户端在使用Socket与远端计算机建立连接时由于指定的地址或端口无效导致无法连接服务端引起的。
System.out.println("正在连接服务端...");
Socket socket = new Socket("localhost",8088);//这里可能引发异常
System.out.println("与服务端建立连接!");
绑定异常,该异常通常是在创建ServerSocket时指定的服务端口已经被系统其他程序占用导致的.
System.out.println("正在启动服务端...");
ServerSocket serverSocket = new ServerSocket(8088);//这里可能引发异常
System.out.println("服务端启动完毕");
套接字异常,链接重置。这个异常通常出现在 Socket 进行的TCP链接时,由于远端计算机异常断开(在没有调用socket.close()
的之前直接结束了程序)导致的。
socket.close()
方法,此时会进行TCP的挥手断开动作。socket.close()
前不被强制杀死。中断异常,这个异常通常在一个线程调用了会产生阻塞的方法处于阻塞的过程中,此时该线程的interrupt()
方法被调用。那么阻塞方法会立即抛出中断异常并停止线程的阻塞使其继续运行。
例如:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
如果线程t1调用Thread.sleep(1000)处于阻塞的过程中,其他线程调用了t1线程的inerrupt()
方法,那么t1调用的sleep()方法就会立即抛出中断异常InterruptedException并停止阻塞。
没有这个元素的异常,该异常通常发生在使用迭代器Iterator遍历集合元素时由于没有先通过hasNext()方法判断存在下一个元素而贸然通过next()获取下一个元素时产生(当集合所有元素都经过迭代器遍历一遍后还使用next获取)。
while(it.hasNext()){
String str = (String)it.next();
//这里就可能产生NoSuchException异常
System.out.println(it.next());
}
上述代码中循环遍历时,每次调用hasNext()
确定存在下一个元素时,循环里面连续调用过两次next()
方法,这意味着第二次调用next()
方法时并没有判断是否还存在.所以在最后会出现异常。
保证每次调用next()
方法前都确定hasNext()
为true
才进行即可。
并发修改异常,这个异常也经常出现在使用迭代器遍历集合时产生.
当我们使用一个迭代器遍历集合的过程中,通过集合的方法增删元素时,迭代器会抛出该异常.
while(it.hasNext()){
//出现ConcurrentModificationException
String str = (String)it.next();
if("#".equals(str)){
c.remove(str);//遍历过程中不要通过集合方法增或删元素
}
System.out.println(str);
}
使用迭代器提供的remove()
方法可以删除通过next()
获取的元素.
while(it.hasNext()){
String str = (String)it.next();
if("#".equals(str)){
// c.remove(str);
it.remove();
}
System.out.println(str);
}
不支持的操作异常,该异常出现在很多的API中。
例如:常出现在我们对数组转换的集合进行增删元素操作时抛出。
String[] array = {"one","two","three","four","five"};
System.out.println("array:"+ Arrays.toString(array));
List<String> list = Arrays.asList(array);//将数组转换为一个List集合
System.out.println("list:"+list);
list.set(0,"six");
System.out.println("list:"+list);
//对该集合的操作就是对原数组的操作
System.out.println("array:"+ Arrays.toString(array));
//由于数组是定长的,因此任何会改变数组长度的操作都是不支持的!
list.add("seven");//UnsupportedOperationException