Loading...

Java SE入门(十六)——异常处理、函数式接口和Lamda表达式

  iwehdio的博客园:https://www.cnblogs.com/iwehdio/

1、异常处理

异常:代码在编译或运行时出现的错误。

  • 异常包含了错误的类型、原因和位置。

  • 异常的体系结构:

    • Throwable() ,所有异常的顶层。
      • Error :出现的不能处理的严重问题。
      • Exception :可以处理的问题。
  • 异常的处理方式:

    • 不处理异常:JVM帮助处理,显示异常的类型、原因和位置,并且终止程序。
    • 具体处理异常的手段:捕获处理和抛出处理。
  • 捕获处理:

    • 根据已知可能出现的异常类型, 出入异常对象。

    • try ... catch 语句

      try {
          有可能出问题的代码;
      } catch(传入的异常对象) {
          处理异常;
      }
      
    • 执行顺序:先执行 try 中的语句;如果发生异常,异常下边的代码不再执行;跳入 catch 中的语句;如果没有发生异常,只执行 try 中的语句,不执行 catch 中的语句。

    • Eclipse辅助编写:右键 > Surround with。

  • 抛出处理:

    • 不想或没有能力处理异常时,此时谁调用方法,谁处理异常。

    • 使用关键字 throws 关键字在方法的声明中抛出异常。

      public void function() throws Exception {}
      
    • 从主方法中抛出异常,是由 JVM 虚拟机处理。

  • 如何处理多个异常:

    • 可以使用多个 try ... catch 语句。

    • 可以使用一个 try 和多个 catch 语句。

      try {
          有可能出问题的代码1;
          有可能出问题的代码2
      } catch(传入的异常对象1){
          处理异常1;
      } catch(传入的异常对象2) {
          处理异常2;
      } catch(Exception e) {
          处理通用异常;
      }
      
    • 多个 catch之间的顺序:

      • 多个 catch 中传入的异常对象可能有子父类关系。
      • 同级的异常对象没有顺序关系。
      • 父类异常对象一定在子类的后面。
  • Throwable 类:

    • String getMessage():出现异常的原因。
    • String toString():出现异常的类型和原因。
    • void printStackTrace():出现异常的类型、原因和位置。
  • finally 关键字:

    • 组合 try ... catch 语句,在最后的位置。用于释放资源等收尾工作。

    • 无论 try ... catch 语句如何执行,finally 语句一定执行。

      try {
          有可能出问题的代码;
      } catch(传入的异常对象) {
          处理异常;
      } finally {
          收尾工作;
      }
      
    • IO流异常处理,例:

      FileWriter fw = null;			// 在外部声明并初始化,防止
      try {
          System.out.println(2 / 0);		//异常1
          fw = new FileWriter("A.txt");
          fw.writer("A");
          System.out.println(2 / 0);		//异常2
          fw.writer("B");
      } catch(IOException e) {
          e.printStackTrace();
      } finally {					//无论是否发生异常都要close()
          try {
              if(fw != null){		//如果发生异常1,不能对空引用调用方法
                  fw.close();
              }
          } catch(IOException e) {
          	e.printStackTrace();
          }
      }
      
  • 异常的分类:

    • 运行时期异常:RuntimeException 的子类,在编译时期可以选择处理或不处理。
    • 编译时期异常:是Exception的子类,且不是 RuntimeException 的子类在编译时期必须处理。
  • throw 关键字:制造异常的方式,并且结束方法,可用于自定义异常。

    • 要求输入在 0~100,例:

      public static void checkScore(int score) {
          if(score < 0 || score > 100){
              throw new RuntimeException("不在0~100之间");
          }
          System.out.println("在0~100之间");	
      }
      
    • 自定义异常类:实现创建一个类并实现多个构造方法,(如果是编译时异常,RuntimeException 改为 Exception)。

      public class MyException extends RuntimeException{
          public MyException() {
              super();
          }
          public MyException(String s) {
              super(s);
          }
      }
      
    • 如果抛出(throw)的是编译时期异常,必须在方法声明处抛出(throws)。

2、递归

将大问题拆成小问题,然后把小问题拆成可以解决的更小的问题,最终解决大问题

  • 递归的注意事项:

    • 一定要有出口(最小的问题可以解决)。
    • 递归次数不宜过多,防止内存溢出。
  • 求阶乘,例:

    public static int JC(int n) {
        if(n == 1) {
            return 1;
        } else {
            return n * JC(n - 1);
        }
    }
    
  • 斐波那契数列,例

    public static int Fib(int n) {
        if(n == 1 || n == 2) {
            return 1;
        } else {
            return Fib(n - 1) + Fib(n - 2); 
        }
    }
    

3、函数式接口

  • 函数式接口:有且只有一个抽象方法的接口。适用于Lamda表达式。
  • 在JDK8以上,接口中可以添加静态方法或非抽象的实例方法。
    • 在实例方法的申明中,需要增加default关键字修饰,因此这种方法也称为默认方法。
    • 非抽象的实例方法是接口自带的方法。接口被实现后,实例可以直接使用这些默认方法,同时如果对默认方法需要重写时,可以直接重写即可。
  • 在接口上方添加一个 @FunctionalInterface注解,可以检测是否是一个函数式接口。如果不是函数式接口,则会编译失败。
  • Lamda 具有延迟加载的特点。
    • 使用 Lamda 表达式作为参数传递,仅仅是把参数传递到方法中。
    • 只有在方法中调用 Lamda 表达式表达的参数时,才会执行 Lamda 表达式中的代码。
    • 如果有条件判断,导致 Lamda 表达式不执行,这样就对性能进行了优化。

4、常用函数式接口

  • Supplier 接口:

    • 被称为生产型接口,指定的泛型是什么,就返回什么类型的数据。

    • 包含一个无参方法:T get()

    • 示例:

      public static int method(Supplier<Integer> sup) {
          return sup.get;
      }
      
      public static void main(String[] args) {
          int nun = method(() -> {
              return 2020;
          });
          System.out.println(num);
      }
      
  • Consumer 接口:

    • 被称为消费型接口,指定的泛型是什么,就使用什么类型的数据。

    • 包含一个方法:void accept(T t)

    • 默认方法:con1.andThen(con2),可以将两个 Consumer 接口组合到一起,再对数据进行消费。

    • 示例:

      Consumer<String> con1;
      Consumer<String> con2;
      String s = "qwer";
      //谁在前先消费谁(谁调用的方法先消费谁)
      con1.andThen(con2).accept(s);
      //等价于:
      con1.accept(s);
      con2.accept(s);
      
  • Predicate 接口:

    • 对某种类型的数据进行判断,从而得到一个 boolean 返回值。
    • 包含一个方法:boolean test(T t)
    • 默认方法1:pre1.and(pre2),表示与的关系,连接判断条件。是通过逻辑与(&&)实现的。
    • 默认方法2:pre1.or(pre2),表示或的关系,连接判断条件。是通过逻辑或(| |)实现的。
    • 默认方法3:pre.negat(),表示非的关系。是通过逻辑非(!)实现的。
  • Function 接口:

    • 被称为转换型接口,根据一个类型的数据,得到另一个类型的数据。前者为前置条件,后者为后置条件。也可以用于同种数据类型中,既需要参数也需要返回值的情形。

    • 有两个泛型:Function<T, R>,从 T 转换为 R 类型。

    • 包含一个方法:R apply(T t)

    • 默认方法:fun1.andThen(fun2),将两个Function 接口进行组合,即先进行一次转换,再将转换后的结果再进行一次转换。

5、Lamda表达式

  • 标准格式:(参数列表) -> {重写方法的代码}

    • 包括一些参数、一个箭头和一段代码。

    • () 表示接口中抽象方法的参数列表,没有参数则为空。

    • -> 表示将参数传递给方法体。

    • {} 表示重写接口的抽象方法的方法体。

    • 如果有返回值则 return 返回值。

    • 相比匿名内部类,Lamda表达式不会生成 .class 文件。

    • 示例:

      public interface Cook {
          public void makeFood();
      }
      
      public class Demo {
          public static void main(String[] args) {
              invokeCook(() -> {
                  System.out.println("cook");
              })
          }
          
          public static void invokeCook(Cook cook) {
              cook.makeFood();
          }
      }
      
  • Lamda表达式的简化:

    • 参数列表中的数据类型可省略。
    • 参数如果只有一个,那么 () 可以省略。
    • 如果重写方法的代码只有一行,那么可以省略 {} 和 return; 。
  • Lamda表达式的使用前提:

    • 接口中有且只有一个抽象方法,即函数式接口。
    • 必须有上下文推断,方法的参数或局部变量类型必须为Lamda对应的接口类型。

iwehdio的博客园:https://www.cnblogs.com/iwehdio/
posted @ 2020-01-31 11:31  iwehdio  阅读(643)  评论(0编辑  收藏  举报