自定义异常类
系统提供的异常类不足
需求:模拟feiq上线如果没插网线,就抛出一个没插网线的异常,如果,插上网线,正在显示好友列表。
利用ip来判断一下有没有网线这里模拟成字符串。
自定义一个类来继承Exception类:
自做:完成这个ip异常处理
利用父类的Exception来处理异常对象
我们还可以不捕获,继续抛出去,比如main调用,我们就抛给虚拟机
1.演示一个自定义异常,完了把它抛给虚拟机
class Excep
{
public static void main(String[] args) throws NoIpException
{
String ip=null;
/*try{
feiQ(ip);
}catch(NoIpException e)
{
e.printStackTrace();//打印异常栈信息
}*/
feiQ(ip);
}
public static void feiQ(String ip)
{
if(ip==null)
{
throw new NoIpException("没有插网线");
}
System.out.print("正常显示");
}
}
//继承一下老大
class NoIpException extends Exception
{
public NoIpException(String str)
{
super(str);//传递错误信息
}
需求:吃法,10元,没带够钱的异常,如果带够了,就可以吃饭了。
自己来做这样一个异常。
//定义一个没带钱的异常
//把这个异常用在一个方法上
class NoMoneyException extends Exception{
//传入异常信息
public NoMoneyException(String message){
super(message);
}
}
public static void eat(int money) throws NoMoneyException{
if(money < 10){
//函数内部抛出一个异常,函数声明上面我得抛啊
throw new NoMoneyException("我钱不够,我特么吃不了饭");
}else{
System.out.println("我现在可以吃饭了");
}
}
下面来说一下:如果方法内部抛出一个运行时异常,运行时异常在方法上可声明就声明,想处理就处理
Exception:1.运行时异常(通过程序员良好的习惯去避免)2.编译时异常
什么是运行时异常?
除了上面运行时异常,就是编译时异常。
那么多,怎么记?
不用记。
直接用文档查就好了。
上面就是抛出了一个线程中断异常,为什么必须抛出一个线程中断异常呢?而这个异常又是一个编译异常
我们看看wait()本身这个函数
很明显它是抛出了一个线程中断时异常。
我们知道调用一个抛出了异常的方法,我们必须进行处理,要么捕获,要么进行抛出,特别又是编译异常的函数。
下面我们来说另外一个问题:
一个读取,一个删除,能不能成功。明显不能。
说明资源文件一旦使用完毕,一定要释放,不然其他程序将无法操作此文件。这种事情是程序来做的。
就算是读到一半出了异常,也要把文件释放出去,别人才可以来对文件进行操作
finally 块;
finally块的 使用前提是必须要存在try块才能使用。
finally块的代码在任何情况下都会执行的,除了jvm退出的情况。
finally非常适合做资源释放的工作,这样子可以保证资源文件在任何情况下都 会被释放。
第一种: 比较适用于有异常要处理,但是没有资源要释放的。
try{
可能发生异常的代码;
}catch(捕获的异常类型 变量名){
处理异常的代码;
}
第二种:比较适用于既有异常要处理又要释放资源的代码。
try{
可能发生异常的代码;
}catch(捕获的异常类型 变量名){
处理异常的代码;
}finally{
释放资源的代码;
}
第三种: 比较适用于内部抛出的是运行时异常,并且有资源要被释放。
try{
可能发生异常的代码;
}finally{
释放资源的代码;
}
上面就退出了虚拟机,不会执行那个finally块中的代码
下面我们简单来写一个读取文件异常的代码处理:
简单说一下泛型
1。接口泛型
接口泛型是在实现接口的时候指定的类型
当然在实现接口的时候也可以不传递具体的类型,他默认就为Object类型
很可能就是你在用的时候,要手动变为相应的数据类型
2.泛型的上下限
public class UpperBoundedExample {
public static <T extends Number> double sum(List<T> list) {
double sum = 0;
for (T element : list) {
sum += element.doubleValue();
}
return sum;
}
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);
System.out.println("Sum of integers: " + sum(integers));
System.out.println("Sum of doubles: " + sum(doubles));
}
}
在这个例子中,<T extends Number>
表示泛型 T
必须是 Number
类或其子类。这使得 sum
方法可以接受 List<Integer>
和 List<Double>
。
public class LowerBoundedExample {
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 5; i++) {
list.add(i);
}
}
public static void main(String[] args) {
List<Object> objectList = new ArrayList<>();
addNumbers(objectList);
System.out.println("Numbers added to the list: " + objectList);
}
}
在这个例子中,<? super Integer>
表示泛型的类型必须是 Integer
或者 Integer
的父类型。这使得 addNumbers
方法可以接受 List<Object>
或更泛化的类型。
泛型的几个引用规则
1.如果一个接口定义了泛型,普通类(没有泛型接口的类)去实现它的时候必须指明确定的类型
2.但是如果这个类也标明了相应的泛型,就可以不指定类型,后面new的时候在标出具体的类型就可以
class Test2Demo1<K,V> implements Test2.Entry<K,V> {
3.不管是静态方法还是非静态方法,都是按照下面这种格式定义泛型
//在泛型参数上指定上限
public <T extends SomeType> void myMethod(T value) {
// 方法体
}
//在方法参数上指定上限
public <T> void myMethod(List<? extends SomeType> myList) {
// 方法体
}
4.泛型中传入指定类型,这个指定类型也可以包含泛型
public static <K extends Comparable<K>,V> Comparator<Entry<K,V>> comparingByKey()
public interface Comparator<T>我们来看这个Comparator比较器本身就要传入一个泛型
然后我们上面传入的是一个Entry接口实现类,这个实现类又包含了<K,V>泛型
5.在泛型方法中,可以独立于类上声明的新泛型参数
public class Example<T> {
private T value;
// 类级别的泛型参数 T
public Example(T value) {
this.value = value;
}
// 泛型方法,定义了独立于类级别的泛型参数 U
public <U> void printU(U u) {
System.out.println(u);
}
6.在Java的泛型中,通配符的上下限是有限制的。可以使用 extends 关键字指定上限,但不建议使用 super 关键字指定下限。这是因为泛型的下限通配符(super)并不适用于接口。因为接口本身不能继承类,只能继承其他接口
说一下继承关系与实现关系是不同的概念,但是他们都可以被认为是一种类型的关系。
当使用泛型的时候,它的上限与下限都必须落实当可以有具体的类
对于一个接口来说,如果用<? super 接口> ,那么就是说泛型必须是接口的父类,也就是接口去extends另外接口
而另外的接口不是一个具体的类 7. 关于方法返回值强制转换&拼接多个接口的问题 除非这个接口是一个声明式接口,没有任何的实现方法
对上面的返回来说Serializable是被Comparator显示声明实现的 ,并且没有没有任何抽象方法声明
另外说一点,在java中,如果一个接口有默认方法,它的实现类是可以去调用这个方法的。 8.
你说这里为什么也是传入<? super T>传入T或者T的父类呢
假设一个类Entry就是定义了很多的方法比如得到getKey (),getValue(),然后内部还定义了很多的比较器的方法,调用一个方法会返回一个比较器
一个带有K与V的类,比如下面这个类,或者其他的类,全部实现这样一个方法
然后泛型T可能传入的就是一个Node类型,那么比较器可能就是下面的类型
这里的Entry就是它的父类型