JAVA语言与系统设计笔记(从面向对象到异常处理部分)

JAVA语言与系统设计笔记

本文参考书为郭克华《Java程序设计与应用开发》,为郭克华老师上课所做笔记的整理。

ch1.JAVA基础

变量和数据类型

整型:byte(1字节)、short(2字节)、int(4字节)、long(8字节,long表示的数字后加L)

默认情况下,系统看到一个常量,认为是int。如果在变量范围之内,可以赋值,否则报错(丢失精度)。

实型:float(浮点)、double(双精度,应用更广)。

默认情况下,系统看到一个常量,认为是double。直接赋值给float,都会报错(丢失精度),float要专门用F来标记。

字符型:char,用法和C基本相同,字符对应整数。

例:打印1-127对应的字符(ASCII码)。int i; char ch=(char)i;

转义字符:与C相同。 打印:/_ \

布尔型:Java不用0和非0表示真假,用true和false,对应的数据类型:boolean

字符串:C++中一般用字符数组表示字符数组表示字符串,Java中用String类型表示字符串,更加方便,字符串和其他类型可以用+连接,编程更长的字符串。

运算

和C语法相同

算术运算:+、-、*、/、%

关系运算:>、<、>、=、<=、==、!=

逻辑运算:&&、||、!

赋值运算:+=、-=、*=、/=、++、–

逻辑短路:(A && B),和C语言相同

数组

1.定义方式

C语言:int a[5]; //5必须是常量

JAVA:int a[] = new int[5];int[] a = new int[5]; //标准写法,5可以是变量

定义直接赋值:int[] a = new int[]{1,2,3,4}

2.性质

C语言数组名只是个变量,存储了首地址的值,不是指针;(*a,a=a+5是错误的,*(a+5)可以)

JAVA中数组名虽然没有指针概念,但和指针性质相同。JAVA中的数组名性质和C中的指针p类似。

【例】int[] a = new int[5];//内存垃圾 a=new int[4];

3.使用里面的元素

和C语言基本相同。如a[0]=5; JAVA和C相同。

4.二维数组

C:int[3][4]

JAVA:int[][] a= new int[3][4]

int[][] d= new int[3][];

d[0]=new int[5]; d[1]=new int[100]; d[2]=new int[23];

5.for循环的数组元素遍历
int[] numbers = { 2, 3, 5, 7 };
//在for循环中,可以利用“变量类型 变量名称:数组名称”的形式,直接把数组元素赋值给该变量
for (int number : numbers) {
    System.out.println("number = " + number);
}

ch2.面向对象编程(OOP)

类和对象

类是对象的抽象,对象是类的实例。

1.定义类和对象

JAVA里面定义类和C++基本相同,语法有小区别。

C++:

Customer zs; //C++实名对象

Customer *ls = new Customer(); //C++指针对象

JAVA:

Customer zs = new Customer();

类中的属性用变量表示,叫做成员变量,也叫做属性,域或字段(Field)。

类中的功能用函数表示,叫做成员函数,也叫做方法(Method)。

通过类定义一个对象,叫做实例化对象

2.成员函数的定义

语法和C基本相同,比C简单。

返回类型 函数名(参数列表){

​ 函数体

}

对于一个程序来说,可能遇到的异常情况比较多,所以在if语句中先判断异常的情况,我们需要做很多事排除异常的情况,然后确定正常的情况。

3.通过对象访问对象中的成员变量和成员函数(统称成员)

用.号,类似C++中的->。

4.对象名的引用(指针)性质

Customer zs= new Customer();

zs类似于C++中的指针

zs与ls均为对象名;zs=ls,这里指的是ls的首地址给了zs,以后ls变化zs也变化。

5.构造函数(Constructor,构造子)

作用:对对象进行初始化。

总结:

(1)构造函数名称和类名相同,没有返回类型;

(2)构造函数在对象被实例化的时候,自动调用1次,以后不可手动调用

(3)如果一个类中没有定义构造函数,系统自动给一个无参数的空的构造函数;若定义,则该无参数的空的构造函数失效;

(4)用this.成员名来确定该成员是类中成员变量而不是局部变量。

析构函数:对象消亡时调用,可以做一些资源释放的工作。

C++:~类名(){} 在Java中,不需要专门定义析构函数,可以用finalize函数代替:zs=null; System.gc();

class Customer{
   String account;
   double balance;
    Customer(String account,double balance)
    {
        init(account,balance);
    }
    void init(String account,double balance)
    {
        this.account=account;
        this.balance=balance;
    }
}
class Pro1{
    public static void main(String[] args)
    {
        Customer zs = new Customer("张三",0);
        //此处省略1000行
        zs.init("张三",0);
    }
}

函数重载(overload)

1.重载条件

(1)参数个数不同;

(2)个数相同,类型不同;

(3)个数类型相同,顺序不同。

系统自动根据实参类型匹配相应的形参,调用相应函数。两个函数,名称、参数相同,返回类型不同,不能重载。

重载实现了静态的多态性。(静态:虽然只有一个函数名,但是要编写多个函数)

2.练习

编写复数类,实现两个复数相加。

class ComplexNumber{
    int a,b;
    ComplexNumber(int a,int b)
    {
        this.a=a;
        
    }
    ComplexNumber add(ComplexNumber c)
    {
        return new ComplexNumber(a+c.a,b+c.b);
    }
    //ComplexNumber add(ComplexNumber c)
    //{
    //   this.a+=c.a;
    //    this.b+=c.b;
    //    return this;
    //}
    void display()
    {
        //……
    }
}
class Pro1{
    public static void main(String[] args)
    {
        ComplexNumber c1 = new ComplexNumber(5,6);
        ComplexNumber c2 = new ComplexNumber(7,8);
        ComplexNumber c3 = c1.add(c2);
        c3.display();
    }
}

静态变量和静态函数

1.静态变量

类中的成员变量,特性是被该类的所有对象共用

定义:变量前面加入static修饰符。

访问方式:对象名.变量名。由于它有共用性,一般用类名.变量名访问。(在C++中用类名::变量名表示)

​ 静态变量 普通变量

对象名. 可以 可以

类名. 可以 不可以

2.静态函数

在普通函数前增加static修饰符。

作用:一般情况下,完成公共的功能,或者访问静态变量。

  • 静态函数只能访问静态变量,以及自己函数内的局部变量(包含形参),不能访问类里面的非静态成员变量

  • 静态函数的访问方式和静态变量相同(类名.函数名)

    如前面复数相加,可以用ComplexNumber c3 = ComplexNumber.add(c1,c2);来实现。

class Customer{
	double balance;
	static String bankName;
	static void changeBankName(String s)  {  
		bankName = s;
		//balance = 1000;//错
	}
}

**【练习1】**给某个类实例化多个对象,每个对象赋1个编号,从1开始递增。

class Customer{
    int id;
    static int N=0;
    Customer(){N++;id=N;}
}
class Pro1{
    public static void main(String[] args)
    {
        Customer zs = new Customer();
        Customer ls = new Customer();
        System.out.println(zs.id);
    }
}

**【练习2】**软件登录之后,用户可能会打开很多不同界面,这些界面如何记住登录用户的用户名,以便载入相应内容?

需求:如何在不同的对象(界面)之间传递信息。

方法:将需要传递的信息定义为静态变量,一旦赋值,别的对象可以访问。

class LoginInfo
{
    static String account;	//要共享的变量
}
class Online
{
    //直接访问LoginInfo.account(无需传递)
}
class Chat
{
    //直接访问LoginInfo.account(无需传递)
}

​ 静态变量 普通变量

静态函数 可以 不可以

普通函数 可以 可以

面向对象的基本特征

1.封装(Encapsulation)

日常生活中的封装:隐藏细节、保证安全、便于使用。

软件中的封装:

(1)包级别的封装

多个类的管理,可以将类放入包中进行管理,和Windows文件夹类似。

**【1】将类放入包中,可在类定义时,用package 包名;**来确定。包名首字母一般小写;包名可以用.隔开,逻辑上分出包含关系。

package a.b; 表示a包里面的b子包。不可以直接通过新建文件夹和拷贝.class文件来建包,只能通过编译。

**【2】同一个包中的类,可以直接使用。不在同一个包中的类,通过import 类的路径;**来访问,并要确保被导入的类是public类。

注意:import 包名.*;可以表示导入该包中的所有类;import 包名.*;并不能导入其子包中的类。

(2)类级别的封装

public类和默认权限的类

public类:在类的前面增加public修饰符 public class Customer{} 【注】public类所在的文件名一定要和类名相同

性质:能够被包外其他类导入并访问。

默认权限的类:class XXX{}

性质:只能被同一个包中其他类访问。

(3)成员级别的封装

在成员变量或成员函数前加访问控制符,决定该成员的访问权限。

C++:private、protected、public

JAVA和C++类似:private/默认/protected/public

写法:在成员定义时加入访问控制符。举例:

private String account;		//private权限
String name;				//默认
protected String address;	//protected权限
public void query(){}		//public权限

private表示该成员只能在类的内部被访问;

默认表示该成员能被同一个包中的类访问;(private权限+同一个包中其他类访问)

protected:默认权限+包外子类访问;

public:包内、包外所有类访问。


编程过程中,一般情况下,成员变量定义为私有(被继承情况除外),成员函数定义为公有。

读取或给成员变量赋值:

采用public的成员函数解决。一般用get函数来读取,用set函数来赋值(setter和getter函数)。

public void setBalance(double balance)
{
    this.balance = balance;
}
public String getAccount(String account)
{
    return this.account;
}
public String[] getAddress()
{
    return this.address;
}

**【练习】**编写一个类,该类会被很多其他类调用,要确保该类对象在系统中使用的时候不超过1个实例。(单例模式

class TaskManager
{
    private static TaskManager tm = null;
    public static TaskManager getInstance()
    {
        if(tm == null)
        {
            tm = new TaskMannager();
		}
        return tm;
    }
    private TaskManager()
    {
        System.out.println("任务管理器实例化");
    }
    public void show()
    {
        System.out.println("任务管理器显示");
    }
}
class Desktop
{
	public void click()
    {
        TaskManager.getInstance.show();
    }
    public static void main(String[] args)
    {
        Desktop d = new Desktop(); d.click(); d.click();
    }
}
2.继承(Inheritance)
继承概述

C++:class 子类:[访问控制符] 父类{}

Java:class 子类 extends 父类{}

class Dialog{
    int w,h;
    public void show(){}
}
class FontDialog extends Dialog{
    String fontName;
}
class ParaDialog{
    int lineWidth;
}

注意:

(1)父类又叫做基类、超类,子类又叫派生类、扩展类;

(2)子类继承之后,父类中所有的非私有成员可以当成自己的使用;

(3)Java中不支持多重继承(同时继承好几个父类)(C++支持);

(4)子类中可以定义和父类相同的成员,调用时以子类定义的成员为准,这叫做覆盖或重写(override)(注意和overload(重载)区分)。重写不得使成员函数的访问权限更加严格,否则报错。重写可以对某些子类进行个性化。(重写的作用)

**【练习】**在网上下载了一个软件包,包含4个功能;其中,功能1直接使用,功能2在后面添加其他功能,功能3替换成自己的功能,功能4不能在本项目中使用。

class Module{
    public void fun1(){ System.out.println("功能1"); }
    public void fun2(){ System.out.println("功能2"); }
    public void fun3(){ System.out.println("功能3"); }
    public void fun4(){ System.out.println("功能4"); }
}
class MyModule extends Module{
    public void fun2(){ 
        super.fun2();	//调用父类中的fun2();
        System.out.println("其他功能");
    }
    public void fun3(){	System.out.println("自己功能");	}
    public void fun4(){}
    public static void main(String[] args)
    {
        MyModule mm = new MyModule();
        mm.fun1();
    }
}
继承的本质
  • 从现象上:子类实例化之前,系统为这个子类对象单独实例化一个相应的父类对象。(每个子类构造函数调用之前,父类构造函数都会自动调用)如果父类构造函数有参数,必须通过在子类的第一句用**super(参数列表);**给父类的构造函数赋予参数。
    • super和this相对应:super.XX;表示调用父类的成员,this.XX表示调用本类中成员;super()表示调用父类构造函数;this(参数)表示调用自己的构造函数(用于构造函数互相调用的情况,比如如下代码)。
  class Customer{
      Customer(){
          this(3,5); 
      }
      Customer(int a,int b){}
  }
  • 从本质上:子类和父类就是一种组合关系,只是底层用继承的编译器使得其使用起来更加方便。

  • 继承的作用是代码重用

class FontDialog{
    Dialog d = new Dialog();
    FontDialog(){
        System.out.println("FontDialog构造函数");
    }
   	void fun(){d.w = 34;}
  	public static void main(String[] args)
    {
        new FontDialog(); new FontDialog();
    }
}
组合关系从强到弱

(1)最强:继承**【血缘关系】**

class Dialog{}
class FontDialog extends Dialog{}

父类中的非私有成员都可以在子类全范围类重用。

(2)次之:成员级别组合:A类定义为B类的成员(A和B的声明周期相同)【刘关张三结义】

class A{}
class B{
	A.a = new A();
	//其他代码
}

(3)次次之:函数参数级别的组合:A作为B中某个函数的参数,只在函数范围内有用**【大学同学】**

class A{}
class B{
	void fun(A a){/**/}
	//其他代码
}

(4)最弱:函数中使用**【萍水相逢】**

class A{}
class B{
	void fun()
	{
		/**/
		//使用A
	}
}
3.多态(Polymorphism)

一个东西,在不同场景下呈现出不同形态。

静态多态性:重载(Overload)

一个函数名称,在不同实参传入情况下呈现出不同形态。

静态:一个函数名称,但还是要编写多个函数体。

动态多态性

理论基础:父类引用可以指向子类对象

性质:父类引用调用重写成员时,调用的是子类中的成员。

推论:

对于以下两个类:

class Dialog{}

class FontDialog extends Dialog{}

有常见两种形式用于动态多态的操作:

  • 函数定义父类形参,以子类对象作为实参传入

定义:void fun(Dialog d){}

调用:fun(new FontDialog());

  • 函数定义返回父类形参,以子类对象实际返回

定义:

Dialog fun()

{

​ return new FontDialog();

}

调用:Dialog d = fun();

多态性的作用体现在:

  • 一个父类引用,在不同子类对象被指向的情况下,完成相应子类的功能。该思想是软件支持“不修改源代码的情况下二次开发”以及“不修改源代码的情况下,模块可拼装“的基础。

  • 将两个业务类的关系变远,叫做软件工程中的”低耦合“。

**【例】**编写一个类似于Word的软件,窗口上点击菜单,出现一个字体对话框。

​ 代码如下。对于外来类封装,可以在继承的子类中实例化外来类的对象,通过函数调用实现对外来类函数功能的使用,如MyNewDialog类中的函数语句段显示。

class FontDialog extends Dialog{
	public void show(){
		System.out.println("FontDialog显示");		
	}
}
class Dialog{
	public void show(){}
}
class Window{
	public void clickMenu(Dialog d){
		     d.show();
	}
	public static void main (String[] args) {
		Window w = new Window();	w.clickMenu(new MyNewDialog());
	}
}
class MyNewDialog extends Dialog{
	MyFontDialog mfd = new MyFontDialog();
	public void show(){
		mfd.display();
	}
}
class MyFontDialog {
	public void display(){
		System.out.println("自己编写的漂亮的Dialog显示了!");
	}
}
抽象函数与抽象类
  • 在函数前面增加abstract关键字,称为抽象函数。该函数原则上要被重写,否则报错。

  • 含有抽象函数的类叫做抽象类,用abstract来修饰。即abstract class Dialog{}

  • 抽象函数必须被子类重写,除非该子类也是个抽象类

  • 抽象函数没有函数体(类似C++中的纯虚函数)。

  • 抽象类不能被实例化。

【注意】

  • 抽象类中可以有普通函数,则抽象类可以拥有一些自己的功能。抽象类可以写构造函数

  • 抽象类不能被实例化,但它的构造函数可以在子类中初始化某些变量,普通函数可以被子类重用。

  • 抽象类、抽象函数是一种标准化手段。

abstract class Dialog{	
	public Dialog(){ System.out.println("Hello"); }
	public abstract void show();		
	public void fun(){}			
}
class FontDialog extends Dialog{
	public void show(){		System.out.println("FontDialog显示");			}
}
接口
  • 比抽象类更加“抽象”的“类“,叫做接口(interface)

  • 接口和抽象类类似,只不过它里面所有的函数只能是抽象函数(除非子类为抽象类,否则必须被重写)。其中的abstract可以省略。

  • 接口中任何变量只能是常量不能赋值

  • 接口中所有的成员都是public的,其中关键字public可以省略(默认public)。但子类重写函数时不能省略

  • 一个类最多只能继承一个抽象类,但是可以实现(implements)多个接口(子类也叫做实现类),用逗号隔开。也可以在继承一个父类的同时,实现一个或多个接口,此时extends关键字必须位于implements关键字之前。即class 子类 extends 父类 implements 接口1,接口2,…{}

  • 接口起到连接作用,有时也叫“界面”。

interface Dialog{	
	int a=5;//常量
	void show();	
}

class FontDialog implements Dialog{
	public void show(){		
		System.out.println(Dialog.a); 
		//Dialog.a = 5;	 错误
		System.out.println("FontDialog显示");		
	}
}

class Window{
	public void clickMenu(Dialog d){
		     d.show();
	}
	public static void main (String[] args) {
		Window w = new Window();	w.clickMenu(new FontDialog());
	}
}

其他内容

1.final关键字

在类、成员变量、成员函数前增加final关键字。

  • 类前面增加final,该类不能有子类。
  • 成员函数前增加final,该函数不能被重写。
  • 成员变量前增加final,该变量是常量,必须事先赋值不能再次赋值。(类似C语言的const)
2.Object类

​ 在Java中定义一个类时,如果没有用extends明确标明直接父类,那么该类默认继承Object类,因此,Object类是所有类的父类,或者说,Java中任何一个类都是Object的子类。该类有两个作用:

  • Object类中,有一个toString方法,可以给子类一个以字符串展示的机会。

    public class Customer {
        private String account;
        private String cname;
        private double balance;
        public Customer(String name){
            this.name = name;
        }
        public String toString(){
        	return account+"-"+cname+"-"+balance;
        }
        public static void main(String[] args){
        	Customer zs = new Customer("张三");
        	System.out.println(zs);
        }
    }
    

    打印结果为一个字符串。

  • Object类中,有一个equals方法,可以给子类对象一个比较它们是否相等的机会。

    两个对象名,a==b除非a与b指向同一个对象,才返回true;如果要定义两个对象内容相等,就需要重写"equals();"。

    public class Customer {
        private String name;
        private double balance;
        public Customer(String name){
        	this.name = name;
        }
        public boolean equals(Customer cus){
        	if(name.equals(cus.name) && balance == cus.balance){  
                //字符串相等使用equals方法
        		return true;
        }
        	return false;
        }
        public static void main(String[] args){
        	Customer cus1 = new Customer("张三");
        	Customer cus2 = new Customer("张三");
        	System.out.println(cus1.equals(cus2));
        }
    }
    

**【练习】**详细讲解多态性的应用。

编写一个按钮,具有点击功能;编写一个窗口,上面有个按钮。点击按钮,可以让窗口变红或变蓝。以上写模拟代码即可。

class Button{
	ButtonListener bl;
	public void bind(ButtonListener bl){
        //实现绑定
        this.bl = bl; 
    }
	public void click(){
		bl.action(this);
	}
}
interface ButtonListener{
	public void action(Button b);
}
class Window implements ButtonListener{
	Button b1 = new Button();
	Button b2 = new Button();
	public Window(){      b1.bind(this);    b2.bind(this);  }
	public void action(Button b){
		if(b==b1)  
            this.toRed();
		else 
            this.toBlue();
	}
	
	public void toRed(){
		System.out.println("窗口变红");
	}
	public void toBlue(){
		System.out.println("窗口变蓝");
	}
	public static void main (String[] args) {
		Window w = new Window();  w.b2.click();
	}
}

ch3.Java语言核心包

java.lang包

java.lang包,是Java中最基础的核心包,里面包含的是最基础的类。如数学运算、字符串处理等。这个包在默认情况下,系统将其导入,不需要用import导入到程序中就可以直接使用里面的类。

java.lang.Math类

负责数学运算,下面展开介绍随机数相关问题:

  • 数组放置在1-100的数字,要求随机打乱:可以通过1-100按顺序,随机找两个打乱,打乱多次
class MathTest{
	public static void main (String[] args) {
		int[] arr = new int[100];
		for(int i=0;i<100;i++){
			arr[i] = i+1;
		}
		for(int i=0;i<10000;i++){
			int temp;
			int L1 = (int)(Math.random()*100);
			int L2 = (int)(Math.random()*100);
			temp = arr[L1]; arr[L1] = arr[L2];  arr[L2] = temp;
		}
		for(int i=0;i<100;i++){
			System.out.print(arr[i] + " ");
		}
	}
}
  • 公平的赌博游戏,久赌必输

    100元筹码,随机数,0-0.5之间,赢10元,0.5-1之间,输10元。赢满500走人,其中输光退场。

class MathTest{
	public static void main (String[] args) {
		int M = 100;
		while(true){
			double d = Math.random();
			if(d<0.5)   
                M += 10;
			else
                M -= 10;
			System.out.println("当前财产:"  + M);
			if(M==0)    {  System.out.println("输光走人");  break; }
			if(M==500)  {  System.out.println("赢满走人");  break; }
		}
	}
}
java.lang.String类

负责字符串处理

1.初始化字符串,有两种方式:

  • 直接赋值 String s = "China";

    注意:直接赋值,系统为了节省内存,用的是“池机制”,即:String s1 = "China"; String s2 = "China"; 打印s1==s2,输出为true

​ 要判断两个字符串是否相等,应使用s1.equals(s2)

  • 创建字符串对象 String s = new String("China");

2.charAt函数:s.charAt(1),返回h

3.contains函数(boolean类型),若包含则返回true,否则为false

4.indexof函数,返回第一次出现的index(位置)

5.replace函数,返回替换后的结果(返回的是新的字符串,但原先字符串的内容未变化

java.lang.StringBuffer类

负责字符串处理。StringBuffer类是自变型字符串操作之后,自己变化。如:执行语句:

StringBuffer sm = new StringBuffer("China-Hunan"); sm.append("-CSU"); ,sm变化。

而String是非自变型字符串,在字符串频繁操作场合,大大消耗内存。如:sm如果是String,执行语句sm.replace("CSU","中南大学");,sm没变。

基本数据类型的包装类

数据类型 包装类

int Int

float Float

double Double

重要作用:将字符串转成相应的数值

//因为Integer.parseIntd是静态函数,直接对类名.函数名进行操作即可,无需实例化对象。
int i = Integer.parseInt("123");
float f = Float.parseFloat("3.14");	
double d = Double.parseDouble("3.1415926");

若将数值转成字符串,统一用String.valueOf(各类数值);

java.util包

最重要的是Java集合框架(变长数组),共三类:List类、Set类、Map类。

List类

一维变长数组,元素有位置信息,可重复。

ArrayList:底层用数组存储

LinkedList:底层用链表存储

Vector:底层用数组存储,实现了多线程的安全

import java.util.*
ArrayList<String> list = new ArrayList<String>();
list.add("北京");
list.add(2,"巴黎");
System.out.println(list.get(3));
for(String s:list)	//遍历
{
    System.out.println(s);
}					//或使用for(int i = 0; i<list.size(); i++)
  • 用法完全相同(增删改查)

  • 一边插入一边排序:插入排序法

  • 找位置一般用二分法找位置

Set类

一维变长数组,元素无位置信息不可重复。常用的有:HashSet(元素乱序)、LinkedHashSet(元素保序)。

Map类

二维变长数组,常用的有:HashMap、LinkedHashMap

key value

姓名 张三

性别 男

籍贯 湖南长沙

key不可重复,value可重复。若两个不同的对象指定同一个key值,后面的将会把前面的覆盖。

作业:输入一个长字符串,显示里面每个字符出现的次数。

String str = "qqqwwweeeerr111我爱爱爱爱爱你";
Map<Character, Integer> map = new HashMap<>(); //定义Map集合
for (int i = 0; i < str.length(); i++) {
    int count = 0; //初始化count的值
    for (int j = 0; j < str.length(); j++) { // 遍历一次str字符串
        if (str.charAt(i) == str.charAt(j)) {//判断字符串i下标和j下标的字符是否相等,若相等就让count自增
            count++;
        }
    }
    map.put(str.charAt(i), count);	//把下标为i的字符和他的出现次数存进去
}
System.out.println(map);  //输出Map集合

LinkedHashMap可以确保是按照添加进去的顺序进行存储。

ch4.JAVA异常处理

异常的定义

异常【Exception(例外)】:程序在运行过程中出现的不正常现象。

  • 不正常:(1)编译阶段,程序报错-修改代码;(2)运行阶段,程序报错-处理异常。
  • 异常若不进行处理,危害在:(1)程序异常停止;(2)得不到友好的提示。

异常处理三大关键词

1.关键词try、catch

try - catch - finally

​ 个数 1 1…n 0,1

​ 重要性 *** ** *

  • try:将可能出现异常的代码放在try中;

  • catch:将异常出现后,将需要处理的代码放在catch中。即try{}catch(Exception e){}

【细节问题】:

  • try中的代码是业务代码,如果没有问题,不执行catch;如果有异常,略过try中剩余的代码,转而执行catch,执行完毕后,程序继续向下执行,不会终止。

  • 一个try后面至少跟一个catch,可以跟多个catch,用来处理不同的异常。

  • catch(Exception e)即将异常问题一网打尽,该语句若跟别的异常catch并列,应放到最后。

2.Java异常分类
  • NumberFormatException:数值格式异常

  • ArithmeticException:数学计算异常(如除数为0)

  • ArrayIndexOutOfBoundsException:数组越界异常

  • NullPointerException:对象未分配内存异常(如String str = null)

3.拓展应用

异常处理有时候可以解决一些有趣的问题。如:输入一个整数,打印这个数的平方;如果输入格式不对,反复出现输入框,直到输入格式正确,打印平方。

class ExceptionTest{
	public static void main (String[] args) {
		while(true){
			try{
				String str = javax.swing.JOptionPane.showInputDialog("输入整数");
				int N = Integer.parseInt(str);
				int R = N * N;
				System.out.println("结果是:" + R);
				break;		
			}catch(Exception e){}
		}
	}
}
4.关键词finally

和try、catch一起使用的还有一个关键词:finally。

  • finally代码块原理:finally加在catch后面,表示不管是否出现异常,都需要执行的代码。try-catch之后,可以有finally,也可以没有finally。如打开文件、处理文件、关闭文件(finally)。finally块确保了程序的安全性。

    class ExceptionTest{
    	public static void main (String[] args) {
    		try{
    			System.out.println("打开文件");
    			System.out.println("处理文件");  // double a = 10/0;
    		}catch(Exception e){  System.out.println("以上代码出现了异常"); }
    		finally{  System.out.println("关闭文件");  }
    	}
    }
    
  • finally块不是可有可无的,只要有try,不管try里面发生了循环跳出、函数返回等,配套的finally一定会执行,从底层确保了需要执行的代码一定会执行(安全性)

    class ExceptionTest{
    	public static void main (String[] args) {
    		for(int i=1;i<=10;i++){
    			try{
    				System.out.println("AAAAAAA");	
    				if(i==1)  break;
    			}catch(Exception e){ System.out.println("BBBBB");	 }
    			finally { System.out.println("CCCCCCC"); }
    		}
    	}
    }
    
5.关键词throw、throws
  • 异常处理另外两个关键词:throw、throws:抛出。

  • 异常的原理:try{…}catch(Exception e){…}
    原理:try里面的代码,如果出现异常,系统底层将其包装成一个对象,抛出。被catch块捕获赋值给参数e,并执行catch块。

【例】编写一个函数“setAge”,输入一个人的年龄整数,如果在0-100之间,返回年龄本身数值;否则返回“年龄范围错误”。

class ExceptionTest{
	public int setAge(int age) throws Exception{
		if(age<0 || age>100) {
		    Exception e = new Exception("年龄范围错误");
		    throw e;
		}
		return age;
	}	
	public static void main (String[] args) {
		ExceptionTest et = new ExceptionTest();
		try{ 
			int age = et.setAge(1000);
		}catch(Exception ex){  System.out.println(ex.getMessage()); }
	}
}
  • throw表示在函数中抛出一个实际的异常对象,throws表示在函数定义上标记该函数可能抛出异常。

  • 标记了throws的函数,在调用时,(1)原则上必须用try包围,并编写catch代码处理可能出现的异常(还有非原则情况,即原来的函数抛出的异常类型是RuntimeException的子类),这叫做就地捕获;(2)或者将异常再次向前抛出

  • throws和throw一般用于自定义异常信息并要求从函数中返回的情况。为了不影响函数的正常返回,将自定义异常的信息用异常包装,throw抛出,函数用throws标记。

class ExceptionTest{
	public int setAge(int age) throws Exception{  //异常的向前抛出
		if(age<0 || age>100) {
		    Exception e = new Exception("年龄范围错误");
		    throw e;
		}
		return age;
	}
	public void test () throws Exception{  		//异常的向前抛出
		this.setAge(1000);		
	}
	public static void main (String[] args) {		
		ExceptionTest et = new ExceptionTest();
		try{et.test();} 				   	//异常的就地捕获
		catch(Exception ex){ System.out.println(ex.getMessage());}
	}
}
  • 异常处理使用场合更多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值