Java复习系列(三)
文章目录
3.Java核心技术
3.1异常
在Java中,所有的异常类都有一个祖先类,java.lang包中的Throwable类,它又分为两个子类,分别是Exception(异常)和Error(错误)。
Error类,简而言之,这类错误往往不在程序员的代码思路上,而是Java虚拟机(JVM)出了问题,比如说一个变量的类型定义与它的用法相违背,JVM是无法判断并检测这类问题的。
Exception(异常),这类错误一般是程序可以处理的错误。
其下有几个重要异常子类。
RuntimeException,由JVM虚拟机抛出,运行时异常。
NullPointerException,没有任何引用对象(俗话说的空指针)
ArithmeticException,算数异常,如一个整数除以0.
ArrayIndexOutOfBoundsException,下标越界,新手的老朋友了。

3.1.1 Throwable 类常用方法
public string getMessage() :返回异常发生时的简要描述
public string toString() :返回异常发生时的详细信息
public string getLocalizedMessage() :返回异常对象的本地化信息。
使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。
如果子类没有覆盖该方法,则该方法返回的信息与getMessage() 返回的结果相同
public void printStackTrace() :在控制台上打印 Throwable 对象封装的异常信息
3.1.2 try-catch-finally
try 块: 用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally块。
catch 块: 用于处理 try 捕获到的异常。
finally 块: 无论是否捕获或处理异常,finally 块里的语句都会被执行。
当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。
在以下 4 种特殊情况下,finally 块不会被执行:
- 在 finally 语句块第一行发生了异常。 因为在其他行,finally 块还是会得到执行
- 在前面的代码中用了 System.exit(int)已退出程序。 exit 是带参函数 ;若该语句在异常语句之后,finally 会执行.
- 程序所在的线程死亡。
- 关闭 CPU
注意: 当 try 语句和 finally 语句中都有 return 语句时,在方法返回之前,finally 语句的内容将被执行,并且 finally 语句的返回值将会覆盖原始的返回值。如下:
public class Test {
public static int f(int value) {
try {
return value * value;
} finally {
if (value == 2) {
return 0;
}
}
}
}
最终输出的是0因为try中的return值被finally中的return值覆盖了。
3.1.3. 使用 try-with-resources 来代替 try-catch-finally
《Effecitve Java》 中明确指出:
面对必须要关闭的资源,我们总是应该优先使用try-with-resources而不是 try-finally 。
随之产生的代码更简短,更清晰,产生的异常对我们也更有用。
try-with-resources 语句让我们更容易编写必须要关闭的资源的代码,若采用 try-finally 则几乎做不到这点。
Java 中类似于 InputStream 、 OutputStream 、 Scanner 、 PrintWriter 等的资源都需要我们调用
close() 方法来手动关闭,一般情况下我们都是通过 try-catch-finally 语句来实现这个需求,如下:
//读取文本文件的内容
Scanner scanner = null;
try {
scanner = new Scanner(new File("D://read.txt"));
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
}
使用Java 7之后的 try-with-resources 语句改造上面的代码
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
当然多个资源需要关闭的时候,使用 try-with-resources 实现起来也非常简单,如果你还是用 trycatch-finally 可能会带来很多问题。
通过使用分号分隔,可以在 try-with-resources 块中声明多个资源。
3.2 多线程
3.2.1 简述线程、程序、进程的基本概念。
线程与进程相似,但线程是一个比进程更小的执行单位。
一个进程在其执行的过程中可以产生多个线程。
与进程不同的是:同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。
3.3.2. 线程有哪些基本状态?

由上图可以看出:
线程创建之后它将处于 NEW(新建) 状态,调用 start() 方法后开始运行,线程这时候处于
READY(可运行) 状态。可运行状态的线程获得了 cpu 时间片(timeslice)后就处于 RUNNING(运
行) 状态。

当线程执行 wait() 方法之后,线程进入 WAITING(等待)状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而 TIME_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis) 方法或 wait(long millis) 方法可以将 Java 线程
置于 TIMED WAITING 状态。当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。
当线程调用同 JDX制作步方法时,在没有获取到锁的情况下,线程将会进入到 BLOCKED(阻塞) 状态。线程在执行Runnable 的 run() 方法之后将会进入到 TERMINATED(终止) 状态。
3.3 I/O流
3.3.1 Java中的I/O流分几种?
1.按照流的流向分,可以分为输入流和输出流;
2.按照操作单元划分,可以划分为字节流和字符流;
3.按照流的角色划分为节点流和处理流。
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
3.3.2 为什么有了字节流还要有字符流?
(不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流操作要分为字节流操作和字符流操作呢?)
答案:字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,而且,如果我们不知道编码类型就很容易出现乱码问题。
所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。
举个例子,如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
3.3.3. BIO,NIO,AIO 有什么区别?
BIO (Blocking I/O): 同步阻塞 I/O 模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机 1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。
线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO (Non-blocking/New I/O): NIO 是一种同步非阻塞的 I/O 模型,在 Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Nonblocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。
NIO 提供了与传统BIO 模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞 I/O 来提升开发速率和更好的维护性;对于高负载、高并发的**(网络)应用**,应使用 NIO 的非阻塞模式来开发.
AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步 IO 的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操JDX制作作,IO 操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,
Netty 之前也尝试使用过 AIO,不过又放弃了。

该博客是Java复习系列第三篇,聚焦Java核心技术。介绍了异常处理,包括Throwable类方法、try-catch-finally及try-with-resources;阐述多线程概念,如线程、进程区别和线程状态;还讲解I/O流分类、字节流与字符流差异,以及BIO、NIO、AIO的区别。

489

被折叠的 条评论
为什么被折叠?



