目录
1.异常:
运行时异常会一直自动throw直到jvm
编译期异常:必须处理,否则编译失败。
运行时异常:可选择处理,但通常是程序错误,应尽量避免发生。
1. throws :
public static void method(String name, int age) throws IOException{ 注意因为IOEecption是File..异常对象的父类所以直接可以用多态只throw父类异常对象
//校验参数的合法性
if (name == null) {
参数不合法
throw new IOException("参数name的值为null, 但是我期望的是不为null!");编译期异常
}
if (age < 0) {
throw new FileNotFoundException("年龄不能为负数");//编译期异常
}
System.out.println(name);
}
public static void show() throws FileNotFoundException, IOException{
method(null, 20);
}
public static void main(String[] args)throws FileNotFoundException, IOException {
show();
}
将异常对象层层throw给调用者直到throw给jvm
注意:如果throw后面存在多个异常 存在继承关系 可以直接throw父类
Exception 是所有异常的的父类 所以可以throw的对象都用 Exception来接收
2.try—catch:
运行时异常和编译期异常都可以用try-catch来处理
处理效果: 如果出错了, 我自己在方法内处理, 一段异常处理后, 代码可以继续执行, 我的调用者并感知不到错误
注意:catch异常对象要注意子类放在父类之前负责根据多态遇到第一个父类直接catch永远不会catch到子类异常对象
public static void show() {
//自己处理可能发生的错误!!!
try {
method("张三", -23);
System.out.println("aaaaaaaaaaa");
} catch (FileNotFoundException e1) {//一旦代码发生了异常,会捕获到一个异常对象, 会把这个异常对象赋值给变量e1
System.out.println(e1);
//处理方案
System.out.println("哦,我错了,以后再也不敢了....");
} catch (IOException e2) {
System.out.println("哦,以后不敢了,给你弄个名字过去...");
} finally {
System.out.println("永远执行的代码....");
}
System.out.println("bbbbbbbbbbbbbbbbbbbbbbbbbb");
}
public static void method(String name, int age) throws FileNotFoundException, IOException {
//校验参数的合法性
if (name == null) {
//参数不合法
throw new IOException("参数name的值为null, 但是我期望的是不为null!");//编译期异常
}
if (age < 0) {
throw new FileNotFoundException("年龄不能为负数");//编译期异常
}
System.out.println(name);
}
注意:
1.如果try{}中的代码没有报错,那么catch不执行
2.try{}中的某一行代码在执行的过程中如果真的出错了,那么try{}中后面的代码将不再执行,而是直接匹配catch
3.try{}catch{}是处理问题,一旦问题处理,后面的代码会继续执行 try-cathch后的语句会继续执行
4.如果多个catch块中的异常类存在继承关系,那么子类写前面, 父类写后面
5.如果多个异常类有继承关系, 可以提供一个catch只捕获父类
6.try-catch经常搭配 finally使用, finally代码块的特点: 不管try{}中的代码有没有报错, 该代码块都会执行, 一般finally是用于释放资源的
7.finally可以不配合catch使用
3.自定义异常:
提供的异常需要见名知意所以要自定义异常
步骤:
1.自定义类,继承Exception或者RuntimeException
2. 提供带参构造
3.使用自定义异常
public class AgeException extends Exception{
public AgeException(){
}
//提供带参数构造
public AgeException(String cause){
//调用父类的带参数构造, 把cause赋值给父类的成员变量
super(cause);
}
}
注意String cause并不会打印在控制台上 调用printStackTrace()时会打印在异常信息里
public static void main(String[] args) {
show();
}
public static void show() {
//快速生成try-catch代码块的: alt+enter
try {
method(-23);
} catch (AgeException e) {
//所有的异常都有一个方法: printStackTrace(): 用于输出错误信息到控制台
e.printStackTrace();
System.out.println("下次知道了, 年龄不能为负数!");
}finally {
System.out.println("一定会执行的代码,不管报不报错!");
}
}
public static void method( int age) throws AgeException{
if (age < 0) {
throw new AgeException("年龄不能为负数!");//编译期异常
}
System.out.println(age);
}
printStackTrace()方法可以打印异常信息到控制台
2.泛型:
1.泛型类:
2.泛型接口:
public class Test {
public static void main(String[] args) {
A<String,Integer> a1 = new B();
a1.show("柳岩",23);
C<Integer,String> c = new C<>();
c.show(123,"abc");
}
}
//含有泛型的接口
interface A<E, T> {
void show(E msg1, T msg2);
}
//定义实现类的时候,使用具体的类型替换接口上声明的泛型
class B implements A<String,Integer>{
@Override
public void show(String msg1, Integer msg2) {
System.out.println(msg1);
System.out.println(msg2);
}
}
class C<K,V> implements A<K,V>{
@Override
public void show(K msg1, V msg2) {
System.out.println(msg1);
System.out.println(msg2);
}
}
注意B和C类创建对象时格式不同!
类B为在实现接口A时 用具体类型替换泛型
类C在创建对象时用具体类型替换泛型
注意:泛型中不支持基本类型,只支持引用类型
3.泛型方法,通配符,上下限:
public static<T> void printMessage(T message){
System.out.println(message);
}
通配符:
class Car{
}
class Byd extends Car{
}
public static void main(String[] args) {
//创建3个集合,存储不同类型的数据
ArrayList<Byd> bs = new ArrayList<>();
ArrayList<Car> cs = new ArrayList<>();
ArrayList<Object> os = new ArrayList<>();
showCars(bs);
showCars(cs);
//showCars(os); 报错, 因为必须是Car或者Car的子类
//showCars2(bs); 报错, 因为必须是Car或者Car的父类
showCars2(cs);
showCars2(os);
}
//上限限定: ? extends Car: 表示 Car 及 Car 的子类
public static void showCars(ArrayList<? extends Car> cars){
for (int i = 0; i < cars.size(); i++) {
System.out.println(cars.get(i));
}
}
//下限限定: ? super Car: 表示 Car 及 Car 的父类
public static void showCars2(ArrayList<? super Car> cars){
for (int i = 0; i < cars.size(); i++) {
System.out.println(cars.get(i));
}
}
3.包装类:
Integer Character
自动装箱:基本数据类型自动转换为引用类型
自动拆箱: 引用类型可以自动转换为基本数据类型
//基于Integer讲解包装类的基本使用
public static void main(String[] args) {
//基本类型的整数转换成包装类型的Integer对象
Integer i1 = new Integer(23);
System.out.println(i1);
Integer i2 = Integer.valueOf(24);
System.out.println(i2);
//自动装箱: 将基本类型数据赋值给包装类型的变量
Integer i3 = 25;
//自动拆箱: 可以把包装类型的变量直接赋值给基本类型的变量
int i4 = i3;
System.out.println(i4);
//基本类型转换成字符串类型
String str = Integer.toString(123);
直接123+""就可以转化为字符串
//这里的toString为Integer自己写的静态方法和重写obj的实例方法重载
System.out.println(str.length());
Integer i5 = 33;
String str2 = i5.toString();
//i5调用的toString为重写Obj类中的实例方法
System.out.println(str2.length());
//把字符串类型的数据转换成对应的基本类型
int number = Integer.parseInt("123");
System.out.println(number+1);
Integer i6 = Integer.valueOf("234");
System.out.println(i6+1);
//对于-128~127之间的数据,Integer有缓存区
Integer i10 = 127;//因为Integer有缓存, 去缓存区查找有没有已经存在一个对象的内容为127, 没有, 新创建一个,使用, 放到缓存区
Integer i11 = 127;//因为Integer有缓存, 去缓存区查找有没有已经存在一个对象的内容为127, 有, 复用
System.out.println(i10 == i11);// 比较地址值 true,
}
Byte Short 的缓存区还是 -128 - 127 Characater的缓存区为 0到127
4. 集合:
1.集合的体系结构:
Collection为所有单列集合的父接口 List为数组集合和链表集合的父类接口
如下为Cllection接口实现的规范:(数组集合和链表集合中都重写了这些抽象方法)
public static void main(String[] args) {
Collection<String> cs = new ArrayList<>();
//添加元素 add(E e)
cs.add("古力娜扎");
cs.add("迪丽热巴");
cs.add("马尔扎哈");
//清空集合 clear()
//cs.clear();
//删除指定的严肃
cs.remove("迪丽热巴");
//判断是否包含指定的元素 contains(E e)
System.out.println(cs.contains("古力娜扎"));
//判断集合是否为空 isEmpty()
System.out.println(cs.isEmpty());
//获取集合大小 size()
System.out.println(cs.size());
//把集合转换成数组 toArray()
Object[] array = cs.toArray();
System.out.println(array[0]);
System.out.println(cs);
}
2.Collection的遍历方式:
1 .迭代器:
public static void main(String[] args) {
Collection<String> names = new ArrayList<>();
names.add("赵敏");
names.add("小昭");
names.add("素素");
names.add("灭绝");
//1.调用 Collection.iterator()得到迭代器对象 在迭代器对象的底层有一个游标, 默认在集合的第一个位置
Iterator<String> it = names.iterator();
//2.调用 Iterator.hasNext() 判断当前游标指向的位置有没有元素
while (it.hasNext()) {
//4.调用 Iterator.next() 得到当前位置的元素, 并且将游标向后移动一位
String name = it.next();
System.out.println(name);
}
}
names调用iterator这个Collection接口当中的抽象方法 返回一个 Iterator接口的实现类对象
Iterator接口中有抽象方法hasNest 和 nest
2.增强for循环:
增强for循环的本质是迭代器
public static void main(String[] args) {
Collection<String> names = new ArrayList<>();
names.add("赵敏");
names.add("小昭");
names.add("素素");
names.add("灭绝");
/*
for(数据类型 变量名 : 数组/集合){
变量名代表的是当次循环从容器中获取到的元素
}
注意:
1.增强for循环变量的本质: 迭代器
2.数组也可以使用增强for
*/
for(String name : names){
System.out.println(name);
}
//定义数组
String[] arr = {"a","b","c"};
for (String s : arr) {
System.out.println(s);
}
2.for each:
for each的本质为增强for循环
public static void main(String[] args) {
Collection<String> names = new ArrayList<>();
names.add("赵敏");
names.add("小昭");
names.add("素素");
names.add("灭绝");
// void forEach(Consumer<? super E> action) forEach的底层就是增强for
/*
JDK提供的用于消费的接口
interface Consumer{
void accept(T t); 接受一个数据,消费一个数据 方法内想干嘛? 实现的时候想咋写就咋写
}
*/
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("=====");
//Lambda表达式的写法
names.forEach(s -> System.out.println(s));
//Lambda表达式的方法体就是使用一个对象调用了实例方法, 并且 -> 前后参数一致, 此时可以使用实例方法引用 对象 :: 方法名
System.out.println("====");
names.forEach(System.out::println);
}
注意:Consumer接口中的 泛型下限要求为 必须为定义 Collection接口实现类对象时泛型的替代对象或者其父类
3.注意并发修改异常:
3.List集合:
LIst支持用索引操作集合
add 和 remove 方法 和Collection中的抽象方法 形成重载
ArrayList底层实现原理:
LinkedList底层实现原理:
链表节点的定义:
因为链表对首尾增删迅速所有类中新增成员方法头尾增删查