1.Java基础(三)-异常、泛型、匿名内部类、集合

时间:2022-11-17 08:59:20


项目

数据库管理系统StudentSystemV1.0

包名结构:
cn.system.student.ocean888.entity
--实体类 Student.java
cn.system.student.ocean888.manager
--管理类 StudentManager.java
cn.system.student.ocean888.test
--测试类 SystemTest.java
cn.system.student.ocean888.mainProject
--main方法所在类 Index.java

eclipse复制项目tips:

  1. 打开项目所在目录

1.Java基础(三)-异常、泛型、匿名内部类、集合

1.Java基础(三)-异常、泛型、匿名内部类、集合

  1. 复制项目文件夹

1.Java基础(三)-异常、泛型、匿名内部类、集合

  1. 改名

1.Java基础(三)-异常、泛型、匿名内部类、集合

文件夹名和.project文件中的name值都要改

  1. 导入项目

鼠标右击,import导入项目,选择更名之后的项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sr6ajbXV-1623306038338)(F:_笔记\mdpic\1.Java基础(三)]\image-20210514134905335.png)

导入成功

1.Java基础(三)-异常、泛型、匿名内部类、集合

异常

Throwable类

Java中所有异常的超类,在Java中所有的异常,错误的基类就是Throwable类

Throwable

  • Exception 异常
  • Error 错误

Throwable常用方法

Constructor:

  • Throwable()
    Throwable构造方法,Throwable类对象中,存储的异常或者错误信息默认为null
  • Throwable(String message)
    Throwable构造方法,Throwable类对象中,存储的异常或者错误信息为message

Method:

  • String getMessage()
    获取Throwable对象中存储的异常或者错误信息
  • String toString()
    返回当前异常或者错误的简要描述
  • void printStackTrace()
    展示错误的前因后果,[字体是红色的]
package cn.ocean888_a;

public class Demo1 {
public static void main(String[] args) {
Throwable throwable = new Throwable("test");

System.out.println(throwable.getMessage());
System.out.println(throwable.toString());
// throwable.printStackTrace();
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

throwable.printStackTrace

1.Java基础(三)-异常、泛型、匿名内部类、集合

package cn.ocean888_a;

public class Demo1 {
public static void main(String[] args) {
Throwable throwable = new Throwable("test");

test();
}

public static void test() {
new Throwable("throwableTest").printStackTrace();
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

Exception和Error

Exception 异常可以处置

Error 错误,不可处置,只能避免

异常处理

捕获异常

try catch 结构

try catch finally结构

package cn.ocean888_a;

public class Demo1 {
public static void main(String[] args) {
int[] arr = new int[10];
// 算数异常
div(10, 0, arr);
// 算数异常
div(10, 0, null);
// 空指针异常
div(10, 2, null);
}

public static void div(int num1, int num2, int[] arr) {
try {
arr[0] = num1 /num2;
} catch (ArithmeticException e) {
System.out.println("算数异常");
} catch (NullPointerException e) {
System.out.println("空指针异常");
}
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

总结:

  1. 代码中从异常发生的位置开始,之后的代码都不再执行
  2. 代码中有多个异常,可以使用多个catch块进行捕获操作,分类进行处理
  3. 后期可以将异常情况保存下来作为log日志文件
  4. 异常被捕获之后代码可以正常运行

抛出异常

  • throw
    方法内抛出异常
  • throws
    在方法声明位置,告知调用者当前方法有哪些异常抛出
    异常声明需要生成对应的文档注释
package cn.ocean888_a;

public class Demo1 {
public static void main(String[] args) throws ArithmeticException, NullPointerException {
int[] arr = new int[10];
try {
div(10, 0, null);
} catch (ArithmeticException e) {
System.out.println(e);
} catch (NullPointerException e) {
System.out.println(e);
}
}

/**
* 测试除法函数
* @param num1 被除数
* @param num2 除数
* @param arr 保存数组
* @throws ArithmeticException 算数异常
* @throws NullPointerException 空指针异常
*/
public static void div(int num1, int num2, int[] arr) throws ArithmeticException, NullPointerException {

if(num2 == 0) {
// 除数为零算数异常
throw new ArithmeticException("算数异常");
}

if(arr == null) {
// 数组空指针异常
throw new NullPointerException("空指针异常");
}

System.out.println(num1 / num2);
arr[0] = num1 / num2;
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

抛出异常总结:

  1. 一个代码块{}内,有且只能有一个异常
  2. 从throw位置开始,之后的代码不在运行
  3. 代码中存在使用throw抛出异常,在方法声明位置必须告诉调用者这里有什么异常

RuntimeException

运行时异常

1.Java基础(三)-异常、泛型、匿名内部类、集合

自定义异常

自定义异常类名:必须以Exception结尾

package cn.ocean888_a;

public class Demo2 {
public static void main(String[] args) {
// 抛出异常
try {
buyOneFreeOne(false);
} catch (Exception e) {
System.out.println(e);
}
}

public static void buyOneFreeOne(boolean single) throws NoGirlFriendException{
if(single) {
throw new NoGirlFriendException();
}
System.out.println("买一送一");
}
}


// 自定义异常
class NoGirlFriendException extends Exception {
// 无参数构造方法
public NoGirlFriendException() {}

// 有参数构造方法
public NoGirlFriendException(String message) {
super(message);
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

泛型genericity

1.Java基础(三)-异常、泛型、匿名内部类、集合

格式:

<自定义泛型无意义大写英文字母占位符>

例:​​<T> Type <E> Element <K> Key <V> value​

反省可以在方法,类,接口中使用

泛型在方法中使用

使用静态方法的泛型格式:

public static <T> 返回值类型[自定义泛型] 方法名(必须存在一个对应泛型的参数) {
方法体内可以使用泛型
}
package cn.ocean888;

public class Demo1 {
public static void main(String[] args) {
Integer test = test(123);
String test2 = test("你好");
Demo1 test3 = test(new Demo1());
}

/**
* 带有自定义泛型的声明方法
* @param <T> 自定义泛型无意义占位符
* @param t 指定的泛型数据类型,由用户约束
* @return 对应的T类型,具体数据类型由用户约束
*/
public static <T> T test(T t) {
return t;
}
}

整型时

1.Java基础(三)-异常、泛型、匿名内部类、集合

字符串型

1.Java基础(三)-异常、泛型、匿名内部类、集合

总结:

  1. 自定义泛型声明在返回值之前,以保证方法的参数和返回值都可以使用对应的泛型
  2. 方法声明的泛型,在方法中的参数中必须有一个参数是对应声明的自定义泛型,当前参数是用于约束方法内所用使用到泛型的位置对应的具体数据类型是什么
package cn.ocean888;

public class Demo1 {
public static void main(String[] args) {
Integer test = test(123);
String test2 = test("你好");
Demo1 test3 = test(new Demo1());

Integer[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
String[] arr2 = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
printArray(arr1);
printArray(arr2);
}

/**
* 带有自定义泛型的声明方法
* @param <T> 自定义泛型无意义占位符
* @param t 指定的泛型数据类型,由用户约束
* @return 对应的T类型,具体数据类型由用户约束
*/
public static <T> T test(T t) {
return t;
}

public static <T> void printArray(T[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

泛型在类中使用

格式

class 类名<自定义泛型无意义大写字母占位符> {
在类内的成员变量和成员方法都可以使用自定义泛型
建议:成员变量不建议使用自定义泛型
}
package cn.ocean888;

import java.awt.Window.Type;

/**
* 定义一个自定义泛型类
* @author Ocean
*
* @param <T>
*/
class TypeA<T> {
/**
* 使用和类名一致的自定义泛型,需要通过 类对象 来约束
* @param t 对应泛型具体数据类型的参数
* @return 对应泛型具体数据类型的返回值
*/
public T test1(T t) {
return t;
}

public void test2(T t1, T t2) {
System.out.println(t1);
System.out.println(t2);
}
}

public class Demo2 {
public static void main(String[] args) {
/*
* 创建带有自定义泛型类的对象
* TypeA<String> typeA = new TypeA<String>(); Eclipse标准写法
* TypeA<String> typeA = new TypeA<>(); IDEA写法
*/

// 明确告诉编译器,这里泛型对应的具体数据类型是String类型
// 类内所有使用到泛型占位符的位置都是T类型
TypeA<String> typeA = new TypeA<String>();
String test1 = typeA.test1("Paking duck");
System.out.println(test1);
typeA.test2("meat", "fruit");

// 明确告诉编译器,这里泛型对应的具体数据类型是Demo2类型
TypeA<Demo2> typeA2 = new TypeA<Demo2>();
Demo2 test2 = typeA2.test1(new Demo2());
System.out.println(test2);

}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

1.Java基础(三)-异常、泛型、匿名内部类、集合

1.Java基础(三)-异常、泛型、匿名内部类、集合

不推荐这种方法

注意:

  1. 类声明自定义泛型,需要通过创建对象的方式来约束
TypeA<String> typeA = new TypeA<String>(); Eclipse标准写法
TypeA<String> typeA = new TypeA<>(); IDEA写法
  1. 类声明泛型约束之后,在类内的所有成员方法中使用的泛型都是类约束的泛型具体数据类型
  2. 如果没有约束类声明泛型,所有使用到泛型的位置都是object(不推荐使用)
  3. 类声明的自定义泛型不能用于类内的静态方法
    因为静态成员方法是在类文件的加载阶段准备完毕,已经可以明确的保证该方法是可以执行的
    如果使用类声明的自定义泛型,对应泛型的具体数据类型需要在创建类对象之后才可以明确
    当前静态方法在类文件加载阶段无法明确泛型数据类型是哪一个,也就无法保证执行,因为没有对象

泛型在接口中使用

interface 接口名<自定义泛型无意义占位符> {

}
package cn.ocean888;

interface A<T> {
void test(T t);
}

/**
* *方式,类名之后和接口同名自定义泛型,泛型对应的数据类型是需要在创建当前对象时进行约束使用
*
* @author Ocean
*
* @param <T> 遵从接口和接口一致的泛型
*/
class TypeB<T> implements A<T> {
@Override
public void test(T t) {
System.out.println("*模式");
}
}

/**
* 规矩模式,遵从接口时,接口使用泛型对应的具体数据类型已经明确
* 在类内使用接口中缺省属性为public abstract方法时,泛型已经确认
* @author Ocean
*
*/
class TypeC implements A<String> {
@Override
public void test(String t) {
System.out.println("规矩模式");
}
}


public class Demo3 {
public static void main(String[] args) {
/*
* *模式
*/
TypeB<Integer> typeB = new TypeB<Integer>();
typeB.test(10);

TypeB<Character> typeB2 = new TypeB<Character>();
typeB2.test('A');

/*
* 规矩模式
*/
TypeC typeC = new TypeC();
typeC.test("test");
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

  1. 接口声明的泛型,只能用于类内的成员方法
  2. 遵从带有自定义泛型的接口的类,一种可以遵从过程中明确告知泛型具体类型(规矩模式),一种是在创建类对象时明确泛型具体数据类型(*模式)

匿名内部类

Anonymous Inner Type

几种方法的比较

package cn.ocean888_b;

import java.security.PublicKey;

/*
* 匿名内部类
*/

interface A {
void test();
}

/**
* 非abstract修饰TypeA遵从接口A,要求强制实现接口中的test方法
*/
class TypeA implements A {
@Override
public void test() {
System.out.println("普通接口");
}
}

public class Demo1 {
public static void main(String[] args) {
// 一般接口实现
TypeA typeA = new TypeA();
typeA.test();


/*
* A接口的引用a,new调用A接口的构造方法,注意:并不是创建A接口对象
* 大括号{}里面的内容和一个普通类遵从接口A的效果是一模一样的
* 大括号里面的内容可以认为是类的 本体,但是大括号之前没有类名,这就是匿名内部类
*
* new 关键字在内存堆区申请了空间,创建了一个隐含的遵从接口A的匿名内部类对象
* 并且把该对象的空间首地址,赋值给了接口A的引用数据类型变量
* 接口的引用遵从接口的类对象,这就是多态
*/
A a = new A() {
@Override
public void test() {
System.out.println("匿名内部类的对象赋值给接口的引用");
}
}; // 一定注意这里有分号
a.test();


// 匿名内部类的匿名对象直接调用方法
new A() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象直接调用方法");
}
}.test();


// 匿名内部类的匿名对象直接调用方法的参数,推荐使用此方式
testInterface(new A() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象直接调用方法的参数");
}
});
}

/**
* 需要接口A的实现类对象作为方法的参数
*/
public static void testInterface(A a) {
a.test();
}
}

之前项目的排序就可以用匿名内部类的方法去实现

1.Java基础(三)-异常、泛型、匿名内部类、集合

@Test
public void testSortAge() {
StudentManager studentManager = new StudentManager();

studentManager.add(new Student("ocea1n", 28, '男', 99, 98, 97));
studentManager.add(new Student("ocea1n", 38, '男', 99, 98, 97));
studentManager.add(new Student("ocea1n", 48, '男', 99, 98, 97));
studentManager.add(new Student("ocea1n", 58, '男', 99, 98, 97));
studentManager.add(new Student("ocea1n", 68, '男', 99, 98, 97));
studentManager.add(new Student("ocean", 68, '男', 99, 98, 97));

studentManager.selectSortUsingComparator(new MyComparator() {

@Override
public boolean compare(Student stu1, Student stu2) {
return stu1.getAge() > stu2.getAge();
}
});

去代替原来的impl下的文件

如:AgeAscCompare.java文件

package cn.system.student.ocean888.compare.impl;

import cn.system.student.ocean888.compare.MyComparator;
import cn.system.student.ocean888.entity.Student;

public class AgeAscCompare implements MyComparator{

@Override
public boolean compare(Student stu1, Student stu2) {
return stu1.getAge() < stu1.getAge();
}
}

集合

开发中使用数组的弊端

  1. 数组中能够使用的方法非常少,功能方法需要程序员自己完成
  2. 数据类型单一化,不支持多种情况
  3. 数组容量定义之后不能改

集合的优势

  1. 方法多样,功能完善
  2. 数据类型多样化
  3. 容量可变

集合架构

Java中集合的 总接口 Collection

Java中所有和集合有关的内容,都是Collection接口的子接口或者实现类

interface Collection<E>
interface List<E> List接口,有序可重复
class ArrayList<E> 可变长度数组结构
class LinkedList<E> 双向链表结构
class Vector<E> jdk1.0 线程安全的ArrayList,如果不考虑线程安全问题,推荐使用ArrayList

interface Set<E> Set接口,无序不可重复
HashSet<E> 底层存储数据方式采用哈希表
TreeSet<E> 底层存储数据方式采用平衡二叉树

Collection接口下的常用方法

增:
boolean add(E e);
存入元素当前集合对象中,要求的数据类型是E类型,也就是泛型对应的具体数据类型
boolean addAll(Collection<? extends E> c);
括号中的内容就相当于 class Dog extends Animal中Dog被替换为?,? extends E泛型的上限
要求存入的集合c中,存储的元素要么是E类型,要么是E类的子类


删:
void clear();
清空整个集合
boolean remove(Object obj);
删除集合中的指定元素
boolean removeAll(Collection<?> c);
删除两个集合的交集
boolean retainAll(Collection<?> c);
保留两个集合的交集


查:
int size();
返回集合中有效元素个数
boolean isEmpty();
判断当前集合是否为空
boolean contains(Object obj);
判断指定元素在当前集合中是否存在
boolean containsAll(Collection<?> c);
判断集合c是不是当前集合的子集合

实例

package cn.ocean888_b;

import java.util.ArrayList;
import java.util.Collection;

import javax.sound.midi.Soundbank;

public class Demo2 {
public static void main(String[] args) {
/*
* 因为Collection<E>使用一个接口,接口没有自己的类对象
* 需要使用Collection接口的实现类来完成演示过程ArrayList<E>
* 这里就用到了泛型
*/
Collection<String> c = new ArrayList<String>();

c.add("one");
c.add("two");
c.add("three");
c.add("four");

System.out.println(c);

Collection<String> c1 = new ArrayList<String>();
c1.add("first");
c1.add("second");
c1.add("thrid");
c1.add("forth");

System.out.println(c1);
c.addAll(c1);
System.out.println(c);
System.out.println("size:" + c.size());
System.out.println(c.isEmpty());
System.out.println(c.containsAll(c1));
System.out.println(c.contains("forth"));
}
}

1.Java基础(三)-异常、泛型、匿名内部类、集合

ublic class Demo2 {
public static void main(String[] args) {
/*
* 因为Collection使用一个接口,接口没有自己的类对象
* 需要使用Collection接口的实现类来完成演示过程ArrayList
* 这里就用到了泛型
*/
Collection c = new ArrayList();
c.add("one");
c.add("two");
c.add("three");
c.add("four");

System.out.println(c);

Collection<String> c1 = new ArrayList<String>();
c1.add("first");
c1.add("second");
c1.add("thrid");
c1.add("forth");

System.out.println(c1);
c.addAll(c1);
System.out.println(c);
System.out.println("size:" + c.size());
System.out.println(c.isEmpty());
System.out.println(c.containsAll(c1));
System.out.println(c.contains("forth"));
}


[外链图片转存中...(img-qYDORjSg-1623306038356)]