登陆

Java根底 反常、线程

admin 2019-07-18 280人围观 ,发现0个评论

主要内容

反常、线程

教育方针

可以区分程序中反常和过错的差异说出反常的分类

说出虚拟机处理反常的办法

列举出常见的三个运转期反常

可以运用try…catch要害字处理反常

可以运用throws要害字处理反常

可以自界说反常类

可以处理自界说反常类

说出进程的概念

说出线程的概念

可以了解并发与并行的差异

可以敞开新线程

第一章反常

1.1反常概念

反常,便是不正常的意思。在生活中:医师说,你的身体某个部位有反常,该部位和正常比较有点不同,该部位的功用将 受影响.在程序中的意思便是:

反常 :指的是程序在履行进程中,呈现的非正常的状况,终究会导致JVM的非正常中止。

在Java等面向目标的编程语言中,反常本身是一个类,发作反常便是创立反常目标并抛出了一个反常目标。Java处理反常的办法是中止处理。

反常指的并不是语法过错,语法错了,编译不经过,不会发作字节码文件,底子不能运转.

1.2反常体系

反常机制其实是协助咱们找到程序中的问题,反常的根类是 java.lang.Throwable ,其下有两个子类:

java.lJava根底 反常、线程ang.Error与java.lang.Exception ,往常所说的反常指 java.lang.Exception 。

Throwable体系:

Error:严重过错Error,无法经过处理的过错,只能事前防止,比方绝症。

Exception:表明反常,反常发作后程序员可以经过代码的办法纠正,使程序持续运转,是必需求处理的。好 比伤风、阑尾炎。

Throwable中的常用办法:

public void printStackTrace() :打印反常的详细信息。

包括了反常的类型,反常的原因,还包括反常呈现的方位,在开发和调试阶段,都得运用printStackTrace。

public String getMessage() :获取发作反常的原因。

提示给用户的时分,就提示过错原因。

public String toString() :获取反常的类型和反常描绘信息(不必)。

呈现反常,不要严重,把反常的简略类名,拷贝到API中去查。

1.3反常分类

咱们往常说的反常便是指Exception,由于这类反常一旦呈现,咱们就要对代码进行更正,修正程序。

反常(Exception)的分类:依据在编译时期仍是运转时期去检查反常?

编译时期反常:checked反常。在编译时期,就会检查,假如没有处理反常,则编译失利。(如日期格局化反常)

运转时期反常:runtime反常。在运转时期,检查反常.在编译时期,运转反常不会编译器检测(不报错)。(如数学反常)

1.4反常的发作进程解析

先运转下面的程序,程序会发作一个数组索引越界反常ArrayIndexOfBoundsException。咱们经过图解来解析下 反常发作的进程。

东西类

public class ArrayTools {
// 对给定的数组经过给定的角标获取元素。
public static int getElement(int[] arr, int index) { int element = arr[index];
return element;
}
}

测验类

public class ExceptionDemo {
public static void main(String[] args) { int[] arr = { 34, 12, 67 };
intnum = ArrayTools.getElement(arr, 4) System.out.println("num=" + num); System.out.println("over");
}
}

上述程序履行进程图解:

第二章 反常的处理

Java反常处理的五个要害字:try、catch、finally、throw、throws

2.1抛出反常throw

在编写程序时,咱们必需求考虑程序呈现问题的状况。比方,在界说办法时,办法需求承受参数。那么,当调用方 法运用承受到的参数时,首要需求先对参数数据进行合法的判别,数据若不合法Java根底 反常、线程,就应该奉告调用者,传递合法的 数据进来。这时需求运用抛出反常的办法来奉告调用者。

在java中,供给了一个throw要害字,它用来抛出一个指定的反常目标。那么,抛出一个反常详细怎样操作呢?

1.创立一个反常目标。封装一些提示信息(信息可以自己编写)。

2.需求将这个反常目标奉告给调用者。怎样奉告呢?怎样将这个反常目标传递到调用者处呢?经过要害字throw 就可以完结。throw 反常目标。

throw用在办法内,用来抛出一个反常目标,将这个反常目标传递到调用者处,并完毕当时办法的履行。

运用格局:

throw new 反常类名(参数);

例如:

throw new NullPointerException("要拜访的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");

学习完抛出反常的格局后,咱们经过下面程序演示下throw的运用。

public class ThrowDemo {
public static void main(String[] args) {
//创立一个数组
int[] arr = {2,4,52,2};
//依据索引找对应的元素int index = 4;
int element = getElement(arr, index);
System.out.println(element); System.out.println("over");
}
/*
* 依据 索引找到数组中对应的元素
*/
public static int getElement(int[] arr,int index){
//判别 索引是否越界
if(index<0 || index>arr.length‐1){
/*
判别条件假如满意,当履行完throw抛出反常目标后,办法现已无法持续运算。
这时就会完毕当时办法的履行,并将反常奉告给调用者。这时就需求经过反常来处理。
*/
throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
}
int element = arr[index]; return element;
}
}

留意:假如发作了问题,咱们就会throw将问题描绘类即反常进行抛出,也便是将问题回来给该办法的调用者。

那么关于调用者来说,该怎样处理呢?一种是进行捕获处理,另一种便是持续讲问题声明出去,运用throws 声明处理。

2.2Objects非空判别

还记得咱们学习过一个类Objects吗,从前提到过它由一些静态的有用办法组成,这些办法是null-save(空指针安 全的)或null-tolerant(忍受空指针的),那么在它的源码中,对目标为null的值进行了抛出反常操作。

public static T requireNonNull(T obj) :检查指定引证目标不是null。

检查源码发现这儿对为null的进行了抛出反常操作:

public static  T requireNonNull(T obj) { if (oJava根底 反常、线程bj == null)
throw new NullPointerException(); return obj;
}

2.3声明反常throws

声明反常:将问题标识出来,报告给调用者。假如办法内经过throw抛出了编译时反常,而没有捕获处理(稍后解说该办法),那么有必要经过throws进行声明,让调用者去处理。

要害字throws运用于办法声明之上,用于表明当时办法不处理反常,而是提示该办法的调用者来处理反常(抛出反常). 声明反常格局:

修饰符 回来值类型 办法名(参数) throws 反常类名1,反常类名2…{ }

声明反常的代码演示:

public class ThrowsDemo {
public static void main(String[] args) throws FileNotFoundException { read("a.txt");
}
// 假如界说功用时有问题发作需求报告给调用者。可以经过在办法上运用throws要害字进行声明
public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//假如不是 a.txt这个文件
// 我假定 假如不是 a.txt 以为 该文件不存在 是一个过错 也便是反常 throw
throw new FileNotFoundException("文件不存在");
}
}
}

throws用于进行反常类的声明,若该办法或许有多种反常状况发作,那么在throws后边可以写多个反常类,用逗号离隔。


public class ThrowsDemo2 {
public static void main(String[] args) throws IOException { read("a.txt");
}
public static void read(String path)throws FileNotFoundException, IOException { if (!path.equals("a.txt")) {//假如不是 a.txt这个文件
// 我假定 假如不是 a.txt 以为 该文件不存在 是一个过错 也便是反常 throw
throw new FileNotFoundException("文件不存在");
}
if (!path.equals("b.txt")) { throw new IOException();
}
}
}

2.4捕获反常try…catch

假如反常呈现的话,会马上停止程序,所以咱们得处理反常:

1.该办法不处理,而是声明抛出,由该办法的调用者来处理(throws)。

2.在办法中运用try-catch的句子块来处理反常。

try-catch的办法便是捕获反常。

捕获反常:Java中对反常有针对性的句子进行捕获,可以对呈现的反常进行指定办法的处理。捕获反常语法如下:

try{
编写或许会呈现反常的代码
}catch(反常类型 e){
处理反常的代码
//记载日志/打印反常信息/持续抛出反常
}

try:该代码块中编写或许发作反常的代码。

catch:用来进行某种反常的捕获,完结对捕获到的反常进行处理。 留意:try和catch都不能独自运用,有必要连用。

演示如下:

public class TryCatchDemo {
public static void main(String[] args) {
try {// 当发作反常时,有必要有处理办法。要么捕获,要么声明。
read("b.txt");
} catch (FileNotFoundException e) {// 括号中需求界说什么呢?
//try中抛出的是什么反常,在括号中就界说什么反常类型
System.out.println(e);
}
System.out.println("over");
}
/*
*
* 咱们 当时的这个办法中 有反常 有编译期反常
*/
public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//假如不是 a.txt这个文件
// 我假定 假如不是 a.txt 以为 该文件不存在 是一个过错 也便是反常 throw
throw new FileNotFoundException("文件不存在");
}
}
}

怎样获取反常信息:

Throwable类中界说了一些检查办法:

public String getMessage() :获取反常的描绘信息,原因(提示给用户的时分,就提示过错原因。

public String toString() :获取反常的类型和反常描绘信息(不必)。

public void printStackTrace() :打印反常的盯梢栈信息并输出到控制台。

包括了反常的类型,反常的原因,还包括反常呈现的方位,在开发和调试阶段,都得运用printStackTrace。

2.4finally 代码块

finally:有一些特定的代码不论反常是否发作,都需求履行。别的,由于反常会引发程序跳转,导致有些句子履行 不到。而finally便是处理这个问题的,在finally代码块中寄存的代码都是必定会被履行的。

什么时分的代码有必要终究履行?

当咱们在try句子块中翻开了一些物理资源(磁盘文件/网络衔接/数据库衔接等),咱们都得在运用完之后,终究封闭翻开的资源。

finally的语法:

try…catchfinall年会主持稿y:本身需求处理反常,终究还得封闭资源。

留意:finally不能独自运用。

比方在咱们之后学习的IO流中,当翻开了一个相关文件的资源,最终程序不论成果怎样,都需求把这个资源封闭 掉。

finally代码参阅如下:


public class TryCatchDemo4 {
public static void main(String[] args) { try {
read("a.txt");
} catch (FileNotFoundException e) {
//抓取到的是编译期反常 抛出去的是运转期
throw new RuntimeException(e);
} finally {
System.Java根底 反常、线程out.println("不论程序怎样,这儿都将会被履行。");
}
System.out.println("over");
}
/*
*
* 咱们 当时的这个办法中 有反常 有编译期反常
*/
public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//假如不是 a.txt这个文件
// 我假定 假如不是 a.txt 以为 该文件不存在 是一个过错 也便是反常 throw
throw new FileNotFoundException("文件不存在");
}
}
}

当只要在try或许catch中调用退出JVM的相关办法,此刻finally才不会履行,不然finally永久会履行。

2.5反常留意事项

多个反常运用捕获又该怎样处理呢?

1.多个反常别离处理。

2.多个反常一次捕获,屡次处理。

3.多个反常一次捕获一次处理。

一般咱们是运用一次捕获屡次处理办法,格局如下:

try{
编写或许会呈现反常的代码
}catch(反常类型A e){ 当try中呈现A类型反常,就用该catch来捕获. 处理反常的代码
//记载日志/打印反常信息/持续抛出反常
}catch(反常类型B e){ 当try中呈现B类型反常,就用该catch来捕获. 处理反常的代码
//记载日志/打印反常信息/持续抛出反常
}

留意:这种反常处理办法,要求多个catch中的反常不能相同,而且若catch中的多个反常之间有子父类异 常的联系,那么子类反常要求在上面的catch处理,父类反常鄙人面的catch处理。

运转时反常被抛出可以不处理。即不捕获也不声明抛出。

假如finally有return句子,永久回来finally中的成果,防止该状况.

第三章 自界说反常

3.1概述

为什么需求自界说反常类:

咱们说了Java中不同的反常类,别离表明着某一种详细的反常状况,那么在开发中总是有些反常状况是SUN没有界说好的,此刻咱们依据自己事务的反常状况来界说反常类。例如年纪负数问题,考试成绩负数问题等等。

在上述代码中,发现这些反常都是JDK内部界说好的,可是实践开发中也会呈现许多反常,这些反常很或许在JDK中没有界说过,例如年纪负数问题,考试成绩负数问题.那么能不能自己界说反常呢?

什么是自界说反常类:

在开发中依据自己事务的反常状况来界说反常类.

自界说一个事务逻辑反常: RegisterException。一个注册反常类。

反常类怎样界说:

  1. 自界说一个编译期反常: 自界说类 并承继于 java.lang.Exception 。
  2. 自界说一个运转时期的反常类:自界说类 并承继于 java.lang.RuntimeException 。

3.2自界说反常的操练

要求:咱们模仿注册操作,假如用户名已存在,则抛出反常并提示:亲,该用户名现已被注册。 首要界说一个登陆反常类RegisterException:

// 事务逻辑反常
public class RegisterException extends Exception {
/**
* 空参结构
*/
public RegisterException() {
}
/**
*
* @param message 表明反常提示
*/
public RegisterException(String message) { super(message);
}
}

模仿登陆操作,运用数组模仿数据库中存储的数据,并供给当时注册账号是否存在办法用于判别。

public class Demo {
// 模仿数据库中已存在账号
private static String[] names = {"bill","hill","jill"};
public static void main(String[] args) {
//调用办法try{
// 或许呈现反常的代码
checkUsername("nill");
System.out.println("注册成功");//假如没有反常便是注册成功
}catch(RegisterException e){
//处理反常e.printStackTrace();
}
}
//判别当时注册账号是否存在
//由于是编译期反常,又想调用者去处理 所以声明该反常
public static boolean checkUsername(String uname) throws LoginException{ for (String name : names) {
if(name.equals(uname)){//假如姓名在这儿面 就抛出登陆反常
throw new RegisterException("亲"+name+"现已被注册了!");
}
}
return true;
}
}

第四章 多线程

咱们在之前,学习的程序在没有跳转句子的前提下,都是由上至下顺次履行,那现在想要规划一个程序,边打游戏 边听歌,怎样规划?

要处理上述问题,咱们得运用多进程或许多线程来处理.

4.1并发与并行

并发:指两个或多个事情在同一个时间段内发作。

并行:指两个或多个事情在同一时间发作(一起发作)。

在操作体系中,安装了多个程序,并发指的是在一段时间内微观上有多个程序一起运转,这在单 CPU 体系中,每一时间只能有一道程序履行,即微观上这些程序是分时的替换运转,只不过是给人的感觉是一起运转,那是由于分 时替换运转的时间是十分短的。

而在多个 CPU 体系中,则这些可以并发履行的程序便可以分配到多个处理器上(CPU),完结多使命并行履行, 即运用每个处理器来处理一个可以并发履行的程序,这样多个程序便可以一起履行。现在电脑市场上说的多核CPU,便是多核处理器,核 越多,并行处理的程序越多,能大大的进步电脑运转的功率。

留意:单核处理器的计算机肯定是不能并行的处理多个使命的,只能是多个使命在单个CPU上并发运转。同 理,线程也是相同的,从微观角度上了解线程是并行运转的,可是从微观角度上剖析却是串行运转的,即一个 线程一个线程的去运转,当体系只要一个CPU时,线程会以某种次序履行多个线程,咱们把这种状况称之为 线程调度。

4.2线程与进程

进程:是指一个内存中运转的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以一起运转多 个进程;进程也是程序的一次履行进程,是体系运转程序的基本单位;体系运转一个程序便是一个进程从创 建、运转到消亡的进程。

线程:线程是进程中的一个履行单元,担任当时进程中程序的履行,一个进程中至少有一个线程。一个进程 中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

简而言之:一个程序运转后至少有一个进程,一个进程中可以包括多个线程 咱们可以再电脑底部使命栏,右键>翻开使命管理器,可以检查当时使命的进程:

进程

线程

线程调度:

分时调度

一切线程轮番运用 CPU 的运用权,平均分配每个线程占用 CPU 的时间。抢占式调度

优先让优先级高的线程运用 CPU,假如线程的优先级相同,那么会随机挑选一个(线程随机性),Java运用的为抢占式调度。

设置线程的优先级

抢占式调度详解

大部分操作体系都支撑多进程并发运转,现在的操作体系简直都支撑一起运转多个程序。比方:现在我 们上课一边运用编辑器,一边运用录屏软件,一起还开着画图板,dos窗口等软件。此刻,这些程序是 在一起运转,”感觉这些软件好像在同一时间运转着“。

实践上,CPU(中央处理器)运用抢占式调度形式在多个线程间进行着高速的切换。关于CPU的一个核而 言,某个时间,只能履行一个线程,而 CPU的在多个线程间切换速度相对咱们的感觉要快,看上去便是在同一时间运转。 其实,多线程程序并不能进步程序的运转速度,但可以进步程序运转功率,让CPU的运用率更高。

Java运用 java.lang.Thread 类代表线程,一切的线程目标都有必要是Thread类或其子类的实例。每个线程的作用是 完结必定的使命,实践上便是履行一段程序流即一段次序履行的代码。Java运用线程履行体来代表这段程序流。 Java中经过承继Thread类来创立并发动多线程的过程如下:

1.界说Thread类的子类,并重写该类的run()办法,该run()办法的办法体就代表了线程需求完结的使命,因而把

run()办法称为线程履行体。

2.创立Thread子类的实例,即创立了线程目标

3Java根底 反常、线程.调用线程目标的start()办法来发动该线程

代码如下: 测验类:

public class Demo01 {
public static void main(String[] args) {
//创立自界说线程目标
MyThread mt = new MyThread("新的线程!");
//敞开新线程
mt.start();
//在主办法中履行for循环
for (int i = 0; i < 10; i++) { System.out.println("main线程!"+i);
}
}
}

自界说线程类:

public class MyThread extends Thread {
//界说指定线程称号的结构办法public MyThread(String name) {
//调用父类的String参数的结构办法,指定线程的称号
super(name);
}
/**
* 重写run办法,完结该线程履行的逻辑
*/ @Override
public void run() {
for (int i = 0; i Java根底 反常、线程< 10; i++) { System.out.println(getName()+":正在履行!"+i);
}
}
}
请关注微信公众号
微信二维码
不容错过
Powered By Z-BlogPHP