泛型

概述

泛型(Generic):

  • 泛型就是一个标签:<数据类型>
  • 泛型可以在编译阶段约束只能操作某种数据类型。

注意:

  • JDK 1.7 开始之后,泛型后面的申明可以省略不写
  • 泛型和集合都只能支持引用数据类型,不支持基本数据类型。

{ ArrayList<Object> lists = new ArrayList<>(); lists.add(99.9); lists.add('a'); lists.add("Java"); ArrayList<Integer> list = new ArrayList<>(); lists1.add(10); lists1.add(20); }


优点:泛型在编译阶段约束了操作的数据类型,从而不会出现类型转换异常 体现的是 Java 的严谨性和规范性,数据类型,经常需要进行统一


自定义

泛型类

泛型类:使用了泛型定义的类就是泛型类。

泛型类格式:


修饰符 class 类名<泛型变量>{ } 泛型变量建议使用 E , T , K , V

public class GenericDemo {
    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<String>();
        MyArrayList<Integer> list1 = new MyArrayList<Integer>();
        list.add("自定义泛型类");
    }
}
class MyArrayList<E>{
	public void add(E e){}
    public void remove(E e){}
}


泛型方法

泛型方法:定义了泛型的方法就是泛型方法

泛型方法的定义格式:

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

方法定义了是什么泛型变量,后面就只能用什么泛型变量。

泛型类的核心思想:把出现泛型变量的地方全部替换成传输的真实数据类型

public class GenericDemo {
    public static void main(String[] args) {
        Integer[] num = {10 , 20 , 30 , 40 , 50};
        String s1 = arrToString(nums);
     
        String[] name = {"张三","李四","王五"};
        String s2 = arrToString(names);
    }

    public static <T> String arrToString(T[] arr){
        --------------
    }
}

自定义泛型接口

泛型接口:使用了泛型定义的接口就是泛型接口。

泛型接口的格式:

修饰符 interface 接口名称<泛型变量>{ }

public class GenericDemo {
    public static void main(String[] args) {
        Data d = new StudentData();
        d.add(new Student());
        ................
    }
}

public interface Data<E>{
    void add(E e);
    void delete(E e);
    void update(E e);
    E query(int index);
}
class Student{}
class StudentData implements Data<Student>{重写所有方法}


通配符

通配符:?

  • ? 可以用在使用泛型的时候代表一切类型
  • E、T、K、V 是在定义泛型的时候使用代表一切类型

泛型的上下限:

  • ? extends Car:那么 ? 必须是 Car 或者其子类(泛型的上限)
  • ? super Car:那么 ? 必须是 Car 或者其父类(泛型的下限,不是很常见)
//需求:开发一个极品飞车的游戏,所有的汽车都能一起参与比赛。
public class GenericDemo {
    public static void main(String[] args) {
        ArrayList<BMW> bmws = new ArrayList<>();
        ArrayList<AD> ads = new ArrayList<>();
        ArrayList<Dog> dogs = new ArrayList<>();
        run(bmws);
        //run(dogs);
    }
    //public static void run(ArrayList<?> car){}//这样 dou对象也能进入
    public static void run(ArrayList<? extends Car> car){}
}

class Car{}
class BMW extends Car{}
class AD extends Car{}
class Dog{}



不可变

在 List、Set、Map 接口中都存在 of 方法,可以创建一个不可变的集合

  • 这个集合不能添加,不能删除,不能修改
  • 但是可以结合集合的带参构造,实现集合的批量添加

在Map接口中,还有一个ofEntries方法可以提高代码的阅读性

  • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
public class MyVariableParameter4 {
    public static void main(String[] args) {
        // static <E>  List<E>  of(E…elements)  创建一个具有指定元素的List集合对象
        //static <E>  Set<E>  of(E…elements)    创建一个具有指定元素的Set集合对象
        //static <K , V>   Map<K,V>  of(E…elements) 创建一个具有指定元素的Map集合对象

        //method1();
        //method2();
        //method3();
        //method4();

    }

    private static void method4() {
        Map<String, String> map = Map.ofEntries(
                Map.entry("zhangsan", "江苏"),
                Map.entry("lisi", "北京"));
        System.out.println(map);
    }

    private static void method3() {
        Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京");
        System.out.println(map);
    }

    private static void method2() {
        //传递的参数当中,不能存在重复的元素。
        Set<String> set = Set.of("a", "b", "c", "d","a");
        System.out.println(set);
    }

    private static void method1() {
        List<String> list = List.of("a", "b", "c", "d");
        System.out.println(list);

        //集合的批量添加。
        //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
        //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
        ArrayList<String> list3 = new ArrayList<>(List.of("a", "b", "c", "d"));
        System.out.println(list3);
    }
}



异常

基本介绍

异常:程序在"编译"或者"执行"的过程中可能出现的问题,Java 为常见的代码异常都设计一个类来代表。

错误:Error ,程序员无法处理的错误,只能重启系统,比如内存奔溃,JVM 本身的奔溃

Java 中异常继承的根类是:Throwable

异常的体系:
         Throwable(根类,不是异常类)
      /              \
    Error           Exception(异常,需要研究和处理)
                    /            \
                   编译时异常     RuntimeException(运行时异常)

Exception 异常的分类:

  • 编译时异常:继承自 Exception 的异常或者其子类,编译阶段就会报错
  • 运行时异常: 继承自 RuntimeException 的异常或者其子类,编译阶段是不会出错的,在运行时阶段可能出现,编译阶段是不会出错的,但是运行阶段可能出现,建议提前处理

处理过程

异常的产生默认的处理过程解析:(自动处理的过程)

  1. 默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException(算术异常)
  2. 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
  3. 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据
  4. 直接从当前执行的异常点干掉当前程序
  5. 后续代码没有机会执行了,因为程序已经死亡
public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("程序开始。。。。。。。。。。");
        chu( 10 ,0 );
        System.out.println("程序结束。。。。。。。。。。");//不执行
    }
    public static void chu(int a , int b){
        int c = a / b ;// 出现了运行时异常,自动创建异常对象:ArithmeticException
        System.out.println("结果是:"+c);
    }
}

编译异常

基本介绍

编译时异常:继承自Exception的异常或者其子类,没有继承 RuntimeException,编译时异常是编译阶段就会报错,必须程序员编译阶段就处理的。否则代码编译就报错

编译时异常的作用是什么:

  • 是担心程序员的技术不行,在编译阶段就爆出一个错误, 目的在于提醒
  • 提醒程序员这里很可能出错,请检查并注意不要出bug
public static void main(String[] args) throws ParseException {
	String date = "2015-01-12 10:23:21";
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	Date d = sdf.parse(date);
	System.out.println(d);
}



处理机制

throws

在出现编译时异常的地方层层把异常抛出去给调用者,调用者最终抛出给JVM虚拟机,JVM 虚拟机输出异常信息,直接干掉程序,这种方式与默认方式是一样的。

  • 优点:可以解决代码编译时的错误
  • 运行时出现异常,程序还是会立即死亡!

Exception是异常最高类型可以抛出一切异常!

public static void main(String[] args) throws Exception {
    System.out.println("程序开始。。。。");
    String s = "2013-03-23 10:19:23";
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date date = sdf.parse(s);
    System.out.println("程序结束。。。。。");
}


try/catch

可以处理异常,并且出现异常后代码也不会死亡。

  • 自己捕获异常和处理异常的格式:捕获处理
•  try{
  // 监视可能出现异常的代码!
}catch(异常类型1 变量){
  // 处理异常
}catch(异常类型2 变量){
  // 处理异常
}...finall{
//资源释放
}
  • 监视捕获处理异常企业级写法: Exception可以捕获处理一切异常类型!
•  try{
    // 可能出现异常的代码!
}catch (Exception e){
    e.printStackTrace(); // **直接打印异常栈信息**
}

Throwable成员方法: public String getMessage() : 返回此 throwable 的详细消息字符串 public String toString() : 返回此可抛出的简短描述 public void printStackTrace() : 把异常的错误信息输出在控制台

public static void main(String[] args) {
    System.out.println("程序开始。。。。");
    try {
        String s = "2013-03-23 10:19:23";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        InputStream is = new FileInputStream("D:/meinv.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("程序结束。。。。。");
}


规范做法

在出现异常的地方把异常一层一层的抛出给最外层调用者,最外层调用者集中捕获处理!(规范做法) 这种方案最外层调用者可以知道底层执行的情况,同时程序在出现异常后也不会立即死亡(最好的方案)

public class ExceptionDemo{
	public static void main(String[] args){
        System.out.println("程序开始。。。。");
        try {
            parseDate("2013-03-23 10:19:23");
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("程序结束。。。。");
    }
    public static void parseDate(String time) throws Exception{...}
}


运行异常

基本介绍

继承自RuntimeException的异常或者其子类,编译阶段是不会出错的,它是在运行时阶段可能出现的错误,运行时异常编译阶段可以处理也可以不处理,代码编译都能通过!!

常见的运行时异常

  1. 数组索引越界异常: ArrayIndexOutOfBoundsException
  2. 空指针异常 : NullPointerException,直接输出没问题,调用空指针的变量的功能就会报错!
  3. 类型转换异常:ClassCastException
  4. 迭代器遍历没有此元素异常:NoSuchElementException
  5. 算术异常(数学操作异常):ArithmeticException
  6. 数字转换异常: NumberFormatException
public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("程序开始。。。。。。");
        // 1.数组索引越界异常: ArrayIndexOutOfBoundsException。
        int[] arrs = {10 ,20 ,30};
        System.out.println(arrs[3]); //出现了数组索引越界异常。代码在此处直接执行死亡!

        // 2.空指针异常 : NullPointerException。
        String name = null ;
        System.out.println(name); // 直接输出没有问题
        System.out.println(name.length());//出现了空指针异常。代码直接执行死亡!

        /** 3.类型转换异常:ClassCastException。 */
        Object o = "齐天大圣";
        Integer s = (Integer) o;  // 此处出现了类型转换异常。代码在此处直接执行死亡!

        /** 5.数学操作异常:ArithmeticException。 */
        int c = 10 / 0 ; // 此处出现了数学操作异常。代码在此处直接执行死亡!

        /** 6.数字转换异常: NumberFormatException。 */
        String num = "23aa";
        Integer it = Integer.valueOf(num); //出现了数字转换异常。代码在此处执行死亡!

        System.out.println("程序结束。。。。。。");
    }
}



处理机制

运行时异常在编译阶段是不会报错,在运行阶段才会出错,运行时出错了程序还是会停止,运行时异常也建议要处理,运行时异常是自动往外抛出的,不需要手工抛出

运行时异常的处理规范:直接在最外层捕获处理即可,底层会自动抛出!!

public class ExceptionDemo{
    public static void main(String[] args){
        System.out.println("程序开始。。。。");
        try{
            chu(10 / 0);//ArithmeticException: / by zero
            System.out.println("操作成功!");//没输出
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("操作失败!");//输出了
        }
        System.out.println("程序结束。。。。");//输出了
    }
    
    public static void chu(int a , int b)  { System.out.println( a / b );}
}



Finally

用在捕获处理的异常格式中的,放在最后面。

try{
    // 可能出现异常的代码!
}catch(Exception e){
    e.printStackTrace();
}finally{
    // 无论代码是出现异常还是正常执行,最终一定要执行这里的代码!!
}
try: 1次。
catch:0-N次  (如果有finally那么catch可以没有!!)
finally: 0-1次

finally的作用:可以在代码执行完毕以后进行资源的释放操作

资源:资源都是实现了 Closeable 接口的,都自带 close() 关闭方法!

注意:如果在 finally 中出现了 return,会吞掉异常

public class FinallyDemo {
    public static void main(String[] args) {
        System.out.println(chu());//一定会输出 finally,优先级比return高
    }

    public static int chu(){
        try{
            int a = 10 / 2 ;
            return a ;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }finally {
            System.out.println("=====finally被执行");
            //return 111; // 不建议在finally中写return,会覆盖前面所有的return值!
        }
    }
    public static void test(){
        InputStream is = null;
        try{
            is = new FileInputStream("D:/cang.png");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println("==finally被执行===");
            // 回收资源。用于在代码执行完毕以后进行资源的回收操作!
            try {
                if(is!=null)is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


自定义

自定义异常:

  • 自定义编译时异常:定义一个异常类继承 Exception,重写构造器,在出现异常的地方用throw new 自定义对象抛出
  • 自定义运行时异常:定义一个异常类继承 RuntimeException,重写构造器,在出现异常的地方用 throw new 自定义对象抛出!

throws: 用在方法上,用于抛出方法中的异常

throw: 用在出现异常的地方,创建异常对象且立即从此处抛出

//需求:认为年龄小于0岁,大于200岁就是一个异常。
public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            checkAge(101);
        } catch (AgeIllegalException e) {
            e.printStackTrace();
        }
    }

    public static void checkAge(int age) throws ItheimaAgeIllegalException {
        if(age < 0 || age > 200){//年龄在0-200之间
            throw new AgeIllegalException("/ age is illegal!");
            //throw new AgeIllegalRuntimeException("/ age is illegal!");
        }else{
            System.out.println("年龄是:" + age);
        }
    }
}

public class AgeIllegalException extends Exception{
    Alt + Insert->Constructor 
}//编译时异常
public class AgeIllegalRuntimeException extends RuntimeException{
	public AgeIllegalRuntimeException() {
    }

    public AgeIllegalRuntimeException(String message) {
        super(message);
    }
}//运行时异常