泛型
概述
泛型(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 的异常或者其子类,编译阶段是不会出错的,在运行时阶段可能出现,编译阶段是不会出错的,但是运行阶段可能出现,建议提前处理
处理过程
异常的产生默认的处理过程解析:(自动处理的过程)
- 默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException(算术异常)
- 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
- 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据
- 直接从当前执行的异常点干掉当前程序
- 后续代码没有机会执行了,因为程序已经死亡
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的异常或者其子类,编译阶段是不会出错的,它是在运行时阶段可能出现的错误,运行时异常编译阶段可以处理也可以不处理,代码编译都能通过!!
常见的运行时异常:
- 数组索引越界异常: ArrayIndexOutOfBoundsException
- 空指针异常 : NullPointerException,直接输出没问题,调用空指针的变量的功能就会报错!
- 类型转换异常:ClassCastException
- 迭代器遍历没有此元素异常:NoSuchElementException
- 算术异常(数学操作异常):ArithmeticException
- 数字转换异常: 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);
}
}//运行时异常
















