Java 基础语法 Day10

一、异常

1.1异常的基本处理

1.抛出异常:throw

2.捕获异常:try-catch

1.2异常的作用

1.定位程序bug的关键信息

2.可以作为方法内部的一种特殊返回值,通知给上层调用,方便处理

//需求:将两个数的除返回
public class Demo1 {
    public static void main(String[] args) {
        try{
            System.out.println(div(5,0));
            System.out.println("程序运行成功");

        }
        catch(RuntimeException e){
            e.printStackTrace();
            System.out.println("底层方法运行失败");
        }


    }
    
    public static int div(int a , int b){
        if(b==0){ //当出现异常时,返回给上层调用者,还能告知上层调用,底层是否执行成功
            //注意,不能直接在这return,因为必须返回一个int值
            throw new RuntimeException("除数不能为0!"); //抛出运行异常
            //throw new Exception("除数不能为0!") 抛出编译式异常
            //注意,抛出了异常后,必须到上层调用的地方处理异常,使用try-catch语句
        };
        int res = a / b;
        return res;
    }
}

1.2 自定义异常

处理开发中自己的问题,需要自己来定义异常类,来代表某种问题。

可以继承RuntimeException或是直接继承Exception。

语法:

定义一个异常类继承Exception,重写构造器,通过throw new 异常类(XXX)来创建异常对象并抛出。

直接继承编译式异常,在编译阶段就报错,提醒比较激进。

//认识自定义异常
//需求:公司的系统中,接收到年龄大于150岁,就是一个异常
public class ExceptionDemo2 {
    public static void main(String[] args) {
        try{
            printAge(180);
            System.out.println("运行成功");
        }catch(Age_ILLegal_Exception e){
            e.printStackTrace();
            System.out.println("失败了");
        }

    }
    public static void printAge(int age) throws Age_ILLegal_Exception{
        if(age > 120){
            throw new Age_ILLegal_Exception("年龄不能高于120!!!");

        }else{
            System.out.println(age);
        }
    }
}

自定义运行时异常,语法跟上面无异,就是继承的RuntimeException即可。

小区别:编译时异常,必须显式的抛出(方法定义那throws)并处理,runtime不需要显式地抛出和处理。

事实上,继承RuntimeException更好。

1.3异常的处理方案

方案一:底层异常层层往上抛,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提示。推荐

方案二:最外层捕获异常,尝试重新修复,代码如下:

public class ExceptionDemo2 {
    public static void main(String[] args) {
        boolean flag = true;
        while(flag){
            try{
                printAge();
                System.out.println("运行成功");
                flag = false;
            }catch(Age_ILLegal_Exception e){
                e.printStackTrace();
                System.out.println("失败了,再来一遍");
            }
        }
    }

直到运行成功,才把flag设置为false,以避免异常影响。

二、泛型

泛型是:定义类,接口,方法时,同时声明了一个或多个类型变量 如: <E>.

称为泛型类,泛型接口,泛型方法,统称为泛型。

作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及可能出现的异常。

泛型的本质:把具体的数据类型作为参数传递给类型变量E,以约束传递的数据类型。

1.1泛型类

使用了泛型的类型变量,就是泛型类,比如:修饰符 class 类名<类型变量,类型变量。。。。>{}

public class ArrayList<E,T,K,V> (一般用大写)

public class MyArrayList<E> {
    public boolean add(E e) {
        return true;
    }
}
//学会自定义泛型类
//需求:模拟ArrayList集合,自定义一个集合MyList

public class demo2 {
    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>();
        System.out.println(list.add("acssa"));
    }
}//true

1.2泛型接口

修饰符 interface 接口名<类型变量,类型变量。。。>{}

//这就是一个泛型接口,可以操作不同类型的变量:比如老师,学生。

public interface Data <T>{
    void add(T t);
    void remove(T t);
    void update(T t);
    T query(int id);
}
public class StudentData implements Data<student>{

    @Override
    public void add(student student) {

    }

    @Override
    public void remove(student student) {

    }

    @Override
    public void update(student student) {

    }

    @Override
    public student query(int id) {
        return null;
    }
}

StudentData类,来管理学生数据,用它去实现接口即可,StudentData类里的所有方法都重写接口,传入的参数是student。同理,管理老师的数据,新建一个TeacherData类即可。

1.3泛型方法、通配符、上下限

泛型方法:

修饰符<类型变量,类型变量...> 返回值类型 方法名 (形参列表){ }

//目标:学会定义泛型方法,搞清楚作用
//需求:打印任意数组的内容
public class demo {
    public static void main(String[] args) {

    }
    // public static void printArray(int[] arr) {} 如果这样写,只能打印int类型的数组了,不能打印其他类型的数组
    public static <T> void printArray(T[] arr) {
        //使用泛型,自定义数组里的数据类型,
    }
    public static <T> T getMax(T[] arr) {
        return arr[0];
    }
}

通配符:

就是"?"(问号在java中叫做通配符),可以在使用泛型时,代表一切类型。E,T,K,V是在定义泛型的时候使用

泛型上限:

? extends Car : 代表?能接受的必须是Car及其子类

? super Car :代表 ? 能接受的必须是car及其父类

//理解通配符和上下限
//需求,开发一个极品飞车游戏,很多类型的车来比赛
public class demo2 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        go(list);

    }
    public static void go(ArrayList < ? extends Objects> list) {
        //这里是在使用泛型,代表ArrayList里接收的是一切继承Objects的对象

    }

}

1.4泛型支持的类型、包装类

泛型不支持基本数据类型(int ,String,double... ),只能支持对象类型(引用数据类型).

由此引出了包装类,将基本数据类型包装成对象类型,使得泛型可以支持。

包装类:

                        

把基本类型包装成包装类对象:

1.手工包装:

Integer it = Integer.valueof(100);//推荐

2.自动装箱与自动拆箱

自动装箱:基本数据类型的数据可以直接变成包装对象的数据,不需要其他操作
Integer it = 100; 这里就等于 Integer it =  Integer.valueof();
自动拆箱:把包装类型的对象直接给基本类型的数据
Integer it2 = 133;
int it3 = it2;
把133赋值给it3
ArrayList<Integer> list = new ArrayList<>();指定arraylist中只能装整数
list.add(123);添加整数,实际上添加的是包装类对象

包装类本身也具有它的功能

比如:

1.将基本类型的数据转化成字符串类型

int j =23;
String rs = Integer.toString(j); 输出"23"
 

2.把字符串类型的数值,转换成数值本身对应的真实数据类型(常用)

public static int parseInt(String s)

public static Integer valueOf(String s)

这两个方法都可以

String s = 98;

int res = Integer.parseInt(s);
int res = Integer.valueof(s);
把字符串转化成98整数

三、集合框架

集合是一种容器,它的大小可变,十分常用.

集合体系:

Collection:单列集合,每个元素只包含一个值

Map:双列集合,每个元素包含两个值(键值对)

Collection集合的常用功能:

先学Colletion集合的功能,因为它的子类会继承它的功能

3.1Colletion的三种遍历方式

1.迭代器遍历:迭代器是用来遍历集合的专属方式,在JAVA中,迭代器的代表是Iterator

Collection集合获取迭代器的方法:Iterator<E> iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素。

Iterator迭代器中的常用方法:

boolean hasNext() 访问当前位置是否有元素存在,若有,返回true
E next() 用于获取当前位置的元素
public class CollectionTraversal {
    public static void main(String[] args) {
        Collection<Integer> ls = new ArrayList<>();
        ls.add(1);
        ls.add(2);
        ls.add(123);
        System.out.println(ls);

        //1.得到迭代器对象
        Iterator<Integer> it = ls.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        } //问当前元素是否存在!!!取出当前元素移动到下一位,初始默认指向第一个元素的位置
        // 不要以为hasNext是问的下一个元素

2.增强for循环

for (元素的数据类型 变量名 : 数组或者集合){}

3.Lambda表达式

需要结合Collection的forEach方法来完成

        //2.使用forEach方法遍历
        ls.forEach(s -> System.out.println(s));

三种遍历方式的区别:

认识并发修改异常问题:遍历集合的同时,若又存在增删集合元素的行为时可能会出业务异常,这种现象称为并发修改异常问题。

//目标:认识并发修改异常问题,搞清楚每种遍历的区别
public class demo2 {
    public static void main(String[] args) {
        ArrayList<String> ls = new ArrayList<>();
        ls.add("JAVA入门");
        ls.add("宁夏枸杞");
        ls.add("黑枸杞");
        ls.add("高等数学");
        ls.add("特级枸杞");
        //需求:把所有枸杞都删了
  /*      for(int i = 0 ;i < ls.size() ; i ++){
                 String name = ls.get(i);
            if(name.contains("枸杞")){
                ls.remove(name);
            }
        }
        System.out.println(ls); //发现并没有删干净![JAVA入门, 黑枸杞, 高等数学]
        原因:每删除一个元素,后一个元素会补上来,导致漏删。解决方法:倒着遍历,或者正着遍历,每遍历一个元素,i--

   */
        //方案2:对于没有索引的集合,使用迭代器遍历并删除,也存在并发修改异常问题
        //解决方案:使用迭代器自己的方法来删除,不要用集合的方法来删
        Iterator<String> it = ls.iterator();
        while (it.hasNext()) {
            String name = it.next();
            if(name.contains("枸杞")){
                it.remove();
            }
        }
        System.out.println(ls);
        
        //观点:若集合没有索引,想同时遍历并删除,只能使用迭代器;有索引,可以用for遍历并删除
        //增强for循环,只能用来遍历

3.2 List集合

1.List的特点、特有功能

特点:有序,可重复,有索引。

ArrayList和LinkedList他们都有序,可重复,有索引,但他们的底层实现不同,适合的场景不同

2.ArrayList的底层实现

基于数组存储数据。

数组特点:根据索引查询数据快,查询数据通过地址值和索引定位,但是查询任意数据耗时是相同的。

增删数据的效率低:数组的长度是固定的,而ArrayList长度可变,这就导致增数据需要扩容;删数据要一个一个的把删除数据之后的元素前移。

3.LinkedList的底层实现

基于双向链表存储数据

特点:查询慢,无论查询哪个数都要从头开始找

链表的增删相对快,试想LeetCode做过的那些题。

LinkedList常见的应用场景:

实现队列:先进先出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值