JavaSE:文档注释、异常处理、多线程Thread

一、文档注释

1.语法格式:、/** */

2.作用:

用javadoc.exe工具,生成API帮助文档

3.如何使用javadoc.exe生成API

tools菜单–>generate JavaDoc…–>

/**
* 这是程序的入口main方法
* @param args String[] 命令行参数,在运行时可以传入参数值,格式:java 主类名 参数值1 参数值2 。。。
*/

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * 文档注释的演示
 *
 *
 * @author Irene
 * @since 1.0
 * @see java.lang.Object
 */
public class TestJavadoc {

    /**
     * 这是程序的入口main方法
     * @param args String[] 命令行参数,在运行时可以传入参数值,格式:java 主类名  参数值1  参数值2 。。。
     */
    public static void main(String[] args) {

    }

    /**
     * 求两个整数的和
     * @param a int 加数1
     * @param b int 加数2
     * @return int 返回a+b
     */
    public static int sum(int a, int b){
        return a + b;
    }

    /**
     * 复制一个文件
     * @param srcFileName String 源文件路径名
     * @param destFileName String 目标文件路径名
     * @throws FileNotFoundException 当源文件不存在,会抛该异常
     */
    public static void copyFile(String srcFileName,String destFileName) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream(srcFileName);
        //...
    }

    /**
     * @param
     */
    public void test(){

    }
}

二、异常

1、什么是异常?

以下情况不是异常?
(1)语法错误,编译不通过
(2)逻辑错误,正确的输入得不到正确的输出
什么是异常?
正常情况下是可以运行的,程序也没有逻辑错误,但是因为一些因素:
(1)用户的错误输入
(2)网络中断
(3)用户的余额不足
(4)用户的磁盘空间不够

导致程序无法正常运行,甚至发生异常或错误,程序崩溃。

2.异常的额概述

在Java中一切皆对象,包括异常,也是用对象表示的。
异常的根类型是java.lang.Throwable。

API:
Throwable 类是 Java 语言中所有错误或异常的超类。
(1)只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
(2)只有此类或其子类之一才可以是 catch 子句中的参数类型。

Throwable 类在Java中有两大子类:
Error:严重的错误
指一般的合理的应用程序不应该视图捕获的严重错误,例如 :VirtualMachineError(虚拟机错误),
包括StackOverflowError(栈内存溢出)、OutOfMemoryError(堆内存溢出OOM)
如果发生类似的错误,必须停下来,然后修改代码或者是升级硬件。
Exception:一般的异常
指出了合理的应用程序想要捕获的条件。

3.异常的处理 try cath

(1)注意:无论是JVM抛出的异常,还是我们程序员手动抛出的异常,都可以使用try…catch处理。
(2)如何处理,语法格式
try{
可能发生异常的代码
}catch(异常类型1 异常对象名称){//习惯上异常对象名称都叫e
尝试处理异常的代码,
或者是打印异常信息的代码(打印可以是在控制台打印,也可以是输出到日志文件)
}catch(异常类型2 异常对象名称){//习惯上异常对象名称都叫e
尝试处理异常的代码,
或者是打印异常信息的代码(打印可以是在控制台打印,也可以是输出到日志文件)
}。。。。

finally{
最终一定会执行的代码,无论try中是否发生异常,也不管catch是否可以捕获异常,
也不管try…catch中是否有return语句,都一定会执行finally中的代码。

只有一种情况不会执行,在try或catch中有System.exit(0)并执行了,退出JVM。

}

(3)如何运行
情况一:try中没有异常,不需要判断catch,不用进行捕获
情况二:try中发生异常,
首先,try中发生异常的语句后面的代码就不执行了
第二,此句代码就抛出一个异常对象,然后catch就开始尝试捕获,按照顺序判断,是否能够匹配该类型
如果有一个catch分支可以捕获异常,那么说明程序不会挂断,从try…catch下面继续运行。
如果没有一个catch分支可以捕获异常,那么当前方法就会挂掉,把异常抛给调用者。如果已经是main了,那么程序就挂了。

public class TestTryCatch {
    public static void main(String[] args) {

        //选中要try的代码,然后按ctrl + alt + T
        try {
            //从命令行接收2个整数,求他们的商
            //(1)命令行接收的数据,是String类型,所以要先转为int
            int a = Integer.parseInt(args[0]);
            int b = Integer.parseInt(args[1]);
            int result = a/b;
            System.out.println("商:" + result);
        } catch (NumberFormatException e) {
            e.printStackTrace();//打印异常的堆栈跟踪信息
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }

        System.out.println("后面其他的代码");
    }
}

4.throws关键字

情形一:在try中发生异常,有catch捕获异常,程序就正常运行
情形二:当前方法中不适合处理异常,要throws抛给调用者处理,如果直接调用者可以处理,那么在直接调用者处就处理了,
如果不行,接着throws,但是最后在main中如何还不处理,程序会挂了。

2.语法格式:

【修饰符】 返回值类型 方法名(【形参列表】) throws 异常列表{
}

3.异常列表:可以是1个或多个,多个之间使用,分割。、

说明:(1)一般来说,throws抛出的都是编译时异常,很少抛出运行时异常。
因为运行时异常的话,是希望我们程序员尽量避免,通过各种if条件判断,避免运行时异常,或者小心一点。
例如:数组下标越界ArrayIndexOutOfBoundsException,应该可以避免
空指针异常NullPointerException,在用对象调用方法等之前,应该加if(xx != null)判断
类型转换异常ClassCastException,在向下转型之前,应该加if(xx instanceof 类型)判断

  (2)如果throws的是运行时异常,调用者如果不看API或源码,我们可能都不知道该方法throws了异常,效果不明显。
  但是写了呢,ctrl +alt + T,选择try...catch时,可以更明确的catch对应的异常。

  (3)方法重写时,对throws的异常有要求
    父类类中被重写的方法throws的异常 >= 子类中重写的方法throws的异常
    反过来说,
    子类重写时,throws的异常 <= 父类类中被重写的方法throws的异常

方法重写的要求: 子类重写 与 父类被重写比较
(1)方法名:必须相同
(2)形参列表:必须相同
(3)返回值类型:
基本数据类型和void:必须相同
引用数据类型:<=
(4)权限修饰符:>=
(5)不能是这些修饰符:static,final,private等
(6)throws异常类型:<=

public class TestThrows {
    public static void main(String[] args)  {
        try {
            copyFile("d:/1.txt", "d:/atguigu/1.txt");
        } catch (FileNotFoundException e) {
            System.out.println("源文件不存在,请检查...");
        }

        System.out.println("其他的代码");

        try {
            method();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void copyFile(String srcFileName, String destFileName) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream(srcFileName);
        //...
    }

    public static void method(){
        throw new NullPointerException();
    }
}

class Father{
    public void method()throws NullPointerException{
        ///...
    }
}

class Sub extends Father{
    @Override
    public void method() throws NullPointerException {
        //
    }
}
5、throw关键字

作用:手动抛出异常

Java的异常对象有两种情况会抛出:
(1)JVM检测到异常,并且自动抛出
(2)我们在代码中,自己用throw语句抛出
我们手动抛出异常的目的是:(1)提示调用者xx不合适(2)改变程序的执行流程

语法格式:
throw 异常对象;
throw new 异常构造器([…]);

public class TestThrow {
    public static void main(String[] args) {
        Account account = new Account("11111",1000);

        Scanner input = new Scanner(System.in);

        while(true) {
            try {
                System.out.print("请输入金额:");
                double money = input.nextDouble();
                account.withdraw(money);
                break;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
class Account{
    private String id;
    private double balance;

    public Account() {
    }

    public Account(String id, double balance) {
        this.id = id;
        this.balance = balance;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id='" + id + '\'' +
                ", balance=" + balance +
                '}';
    }

    public void withdraw(double money){
        if(money < 0){
            throw new IllegalArgumentException(money + "不能为负数");
        }
        if(money > balance){
            throw new IllegalArgumentException(money + "大于余额");
        }

        balance -= money;
    }
}
6.自定义异常

(1)为什么要自定义异常类型?
一个异常:
①类型名
②message信息
③堆栈跟踪信息
④…
其中类型名是最最关键字的,我们看到这个类型名,就应该知道它发生什么状况了,该从哪个方向去解决。
例如:ArrayIndexOutOfBoundsException
NullPointerException
FileNotFoundException
当我们的项目中,有些情况要抛出异常告诉调用者发生xx事情了,但是现有的系统中的异常类型不能准确的表达我的情况,就需要自定义异常。

(2)如何自定义异常?
第一步:必须继承Throwable或它的子类,一般是继承Exception或,RuntimeException
第二步:建议,我们保留一个无参构造,然后再加一个有参构造,为从父类继承的message赋值
第三步:建议,实现序列化接口(后面再详细讲解序列化接口)

(3)如何使用自定义异常?
要求:只能手动throw

public class TestDefineException {
    public static void main(String[] args) {
        Account account = new Account("11111",1000);

        Scanner input = new Scanner(System.in);

        while(true) {
            try {
                System.out.print("请输入金额:");
                double money = input.nextDouble();
                account.withdraw(money);
                break;
            } catch (MoneyCanNotNativeValueException e) {
                e.printStackTrace();
            } catch (BalanceNotEnoughException e) {
                e.printStackTrace();
            }
        }
    }
}

class MoneyCanNotNativeValueException extends Exception{
    public MoneyCanNotNativeValueException() {
    }

    public MoneyCanNotNativeValueException(String message) {
        super(message);
    }
}

class BalanceNotEnoughException extends Exception{
    public BalanceNotEnoughException() {
    }

    public BalanceNotEnoughException(String message) {
        super(message);
    }
}
class Account{
    private String id;
    private double balance;

    public Account() {
    }

    public Account(String id, double balance) {
        this.id = id;
        this.balance = balance;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id='" + id + '\'' +
                ", balance=" + balance +
                '}';
    }

    public void withdraw(double money) throws MoneyCanNotNativeValueException, BalanceNotEnoughException {
        if(money < 0){
            throw new MoneyCanNotNativeValueException(money + "不能为负数");
        }
        if(money > balance){
            throw new BalanceNotEnoughException(money + "太大,余额不足");
        }

        balance -= money;
    }
}

三、多线程

1、相关名词(了解)

程序:program 它是为了完成一个功能,或者一个目的,选择其中一种编程语言(C,Java,Python等)而编写的一组指令的集合。
它是静态的。
进程:process 它是程序的一次运行。
操作系统会以进程为单位,分配资源(内存等)。每一个进程之间是独立的。
如果两个进程之间要进行数据的通信,那是成本很高的,因为他们之间没有共享的内存位置。
只能通过网络通信,或者是通过外置的硬盘等空间来实现数据的共享。
而且CPU在进程之间的切换的成本也很高。
线程:thread 它是进程中的其中一条执行路径。
即一个进程至少有一个线程(称为单线程程序),也可能是多个线程(称为多线程程序),
同一个进程的多个线程之间是可以有共享的内存,那么线程之间的通信成本就降低了。
而且CPU在同一个进程的多个线程之间切换的成本相对较低。
CPU调度的最小单位是线程。

并发:
早期的电脑是只有一个CPU,并且是单核。
同一时刻,一个CPU只能运行一个线程的指令。但是我们编写的程序有多个线程。
如果说大家按顺序执行,那么就说明是单线程的现象,如果前面有句代码阻塞(例如,等着用户输入,等着从硬盘加载数据)了,后面的代码只能干等着,
这个时候CPU的利用率很低。
为了提高CPU的利用率,那么CPU就先将该线程“暂停”,然后转而去执行其他的线程。
这个时候从宏观角度(人的感觉),好像是多个线程同时执行,但是本质上是轮流执行,或者说是抢夺执行,即从微观(CPU)来说,
是先执行一个线程,再执行一个线程,他们之间是快速的切换,我们都感觉不出来。

并行:
现在的电脑是多个CPU,是多核。
这个时候我们可以把多个线程分别派发给多个CPU分别执行,这个叫做并行处理。

现在的程序是并行+并发。
2、Java程序的线程是什么样的呢?

(1)Java程序生来就是多线程的。
第一:有一个main线程(主线程)
第二:GC线程
第三:异常检测和处理线程

(2)那么我们除了main线程、GC等以外,能否开启其他的线程呢?
可以
四种方式:
方式一:继承Thread类
方式二:实现Runnable接口
方式三:实现Callable接口
方式四:线程池

我们JavaSE阶段只学方式一和方式二。

3、继承Thread类实现多线程

步骤:
(1)定义自己的类,继承Thread类
(2)重写public void run()方法
如何重写?看你这个线程要干什么?
(3)创建线程对象,并且启动这个线程
必须调用start()方法

特别说明:不要手动调用run()

public class TestExtendsThread {
    public static void main(String[] args) {
        MyThread my = new MyThread();
        my.start();//从父类Thread继承的   一旦该线程被启动了,就准备好和main线程强CPU了,“同时”运行
//        my.run();//不要手动调用run(),否则就不是多线程了

        //在main线程中打印1-100之间的奇数
        for (int i=1; i<=100; i+=2){
            System.out.println("main:" + i);
        }
    }
}

class MyThread extends Thread{
    //例如:我要在这个线程中打印1-100之间的偶数
    @Override
    public void run(){
        for (int i=2; i<=100; i+=2){
            System.out.println(i);
        }
    }
}
4、实现Runnable接口

步骤:
(1)编写自己的线程类,实现java.lang.Runnable接口
(2)重写public void run()方法
(3)创建自定义线程对象
(4)创建Thread类的对象,并且把刚刚我们创建的自定义线程对象传给Thread对象
(5)调用Thread类对象的start方法

为什么要调用start方法呢?
是为了调用start0方法,即C语言实现的方法,它是操作系统底层的函数库中的方法,
相当于我们的多线程程序要交给操作系统来管理。

public class TestImplRunnable {
    public static void main(String[] args) {
        MyRunnable my = new MyRunnable();
//        my.start();//没有这个方法

        Thread thread = new Thread(my);
        thread.start();

        //在main线程中打印1-100之间的奇数
        for (int i=1; i<=100; i+=2){
            System.out.println("main:" + i);
        }
    }
}

class MyRunnable implements Runnable{
    //例如:我要在这个线程中打印1-100之间的偶数
    @Override
    public void run(){
        for (int i=2; i<=100; i+=2){
            System.out.println(i);
        }
    }
}
5、使用匿名内部类的方式来继承Thread或实现Runnable
public class TestAnoymous {
    public static void main(String[] args) {
        //一个线程打印奇数
        new Thread(){
            public void run(){
                for(int i=1; i<=100; i+=2){
                    System.out.println("奇数:" + i);
                }
            }
        }.start();

        //一个线程打印偶数
/*        Runnable r = new Runnable(){
            public void run(){
                for(int i=2; i<=100; i+=2){
                    System.out.println(i);
                }
            }
        };
        Thread t = new Thread(r);
        t.start();*/

        new Thread(new Runnable(){
            public void run(){
                for(int i=2; i<=100; i+=2){
                    System.out.println(i);
                }
            }
        }).start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值