Java基础笔记(六)--Lambda表达式和异常

函数式编程与面向对象编程的区别: 函数式编程将程序代码看作数学中的函数, 函数自己是另外一个函数的函数或返回值, 即高阶函数.

Lambda 表达式

示例: 经过匿名类实现计算两个int值的功能
public class HelloWorld {   public static Calculate calculate(char opt)   {     Calculate result;     if(opt == '+')     {       // 匿名类实现Calculate接口
      result = new Calculate() {       // 实现加法运算
      @Override         public int calculateInt(int a, int b) {           return a + b;         }       };     }else     {       result = new Calculate()       {         // 实现减法运算
        @Override         public int calculateInt(int a, int b)         {           return a -b;         }       };     }     return result;   }   public static void main(String[] args)   {     int n1 = 10;     int n2 = 5;     Calculate f1 = HelloWorld.calculate('+');     Calculate f2 = HelloWorld.calculate('-');     System.out.println(f1.calculateInt(n1, n2));     System.out.println(f2.calculateInt(n1, n2));   } }
上例中经过匿名类实现 calculateInt 方法. 如今经过 Lambda 表达式将该方法的 if-else 部分修改成:
if(opt == '+') {   // Lambda 表达式
  result = (int a, int b) ->   {     return a+b;   }; }else {   // Lambda 表达式
  result = (int a, int b) ->   {     return a - b;   }; }
Lambda 表达式是一个匿名函数 (方法) 代码块, 能够做为表达式、方法参数和方法返回值. 其标准语法形式为:
(参数列表) -> {   // Lambda 表达式
}
函数式接口
Lambda 表达式实现的接口不是普通的接口, 是函数式接口, 这种接口只能有一个方法. 为防止在函数式接口中声明多个抽象方法, Java 8 提供了一个声明函数式接口的注解 “@FunctionalInterface”.
Lambda 表达式是一个匿名方法的代码块, 它实现的是在函数接口中声明的方法, 返回的是该接口的一个实例.

Lambda 表达式简化形式

省略参数形式
Lambda 表达式能够根据上下文环境推断出参数类型. 上例中的 if-else 能够修改成:
if(opt == '+') {   result = (a, b) ->   {     return a+b;   }; }else {   result = (a, b) ->   {     return a - b;   }; }
省略参数小括号
Lambda 表达式中参数只有一个时, 能够省略参数小括号.
将接口 Calculable 中的 calculateInt 方法修改成:
int calculateInt(int a);
上例中的 if-else 能够修改成:
if(opt == "square") {   result = a ->   {     return a * a;   }; }
省略 return 和大括号
Lambda 表达式体中只有一条语句时, 能够省略 return 和大括号.
继续上例中的 if-else 能够修改成:
if(opt == "square") {   result = a -> a * a; }

做为参数使用 Lambda 表达式

Lambda 表达式常见用途之一是做为参数传递给方法. 这须要声明参数类型为函数式接口类型.
public class HelloWorld {   public void display(Calculate c, int a)   {     System.out.println(c.squareInt(a));   }   public static void main(String[] args)   {     int n = 12;     HelloWorld h = new HelloWorld();     // 传入 Lambda 表达式做为参数
    h.display(x -> x * x, n);   } } // 定义接口
interface Calculate {   // 计算两个int的值
  int squareInt(int a); }

访问变量

Lambda 表达式能够访问所在外层做用域内定义的变量, 包括成员变量和局部变量.
访问成员变量
public class HelloWorld {   private int value = 10;   private static int staticValue = 5;   public static Calculate add()   {     Calculate result = (int a, int b) ->     {       // add是静态方法, 不能访问非静态变量, 只能访问静态变量
      staticValue++;       int c = a + b + staticValue;       return c;     };     return result;   }   public Calculate sub()   {     Calculate result = (int a, int b) ->     {       staticValue++;       this.value++; //若是不与局部变量冲突, 能够省略this
      int c = a - b - staticValue - this.value;       return c;     };     return result;   } } // 定义接口
interface Calculate {   int calculateInt(int a, int b); }
捕获局部变量
Lambda 表达式访问做用域外层的局部变量时, 会发生 “捕获变量” 状况. Lambda 表达式捕获变量时, 会将变量当成 final 的, 不管该变量是否被 final 修饰.

方法引用

Java 8 以后增长了双冒号 “::” 运算符, 该运算符用于 “方法引用” , 注意不是调用方法. “方法引用” 虽然没有直接使用 Lambda 表达式, 但也与 Lambda 表达式有关, 与函数式接口有关.
方法引用分为: 静态方法的方法引用和实例方法的方法引用. 语法形式以下:
类型名:: 静态方法 // 静态方法的方法引用
类型名:: 实例方法 // 实例方法的方法引用
被引用方法的参数列表和返回值类型, 必须与函数式接口方法的参数列表和返回值类型一致.
public class LambdaDemo {   // 声明被引用的静态方法
  public static int add(int a, int b)   {     return a + b;   }   // 声明被引用的实例方法
  public int sub(int a, int b)   {     return a - b;   }   // 声明使用函数式接口实例为参数的方法
  public static void display(Calculable c, int n1, int n2)   {     System.out.println(c.calculateInt(n1, n2));   }   public static void main(String[] args)   {     int n1 = 10;     int n2 = 5;     // 引用静态方法
    display(LambdaDemo::add, n1, n2);     LambdaDemo ld = new LambdaDemo();     // 引用实例方法
    display(ld::sub, n1, n2);   } } interface Calculable {   int calculateInt(int a, int b); }
方法引用就是使用其余类的方法代替了 Lambda 表达式, 使引用的方法起到 Lambda 表达式的做用.

异常处理

Java 中异常封装成为类 Exception, 此外, 还有 Throwable 和 Error 类. 异常类继承层次如图:
Alt text
异常基类 Throwable 有几个经常使用方法:
String getMessage(): 得到发生异常的详细信息.
void printStackTrace(): 打印异常堆栈跟踪信息.
String toString(): 得到异常对象的描述.
Throwable 有两个子类 Error 和 Exception.
Error
Error 是程序没法恢复的严重错误, 只能让程序终止.
Exception
Exception 是程序能够恢复的异常. 该类能够分为: 受检查异常和运行时异常.
受检查异常
编译器会检查这类异常是否进行了处理, 即要么捕获 (try-catch 语句), 要么抛出 (经过在方法后声明 throws), 不然会发生变异错误.
运行时异常
编译器不检查这类异常是否进行了处理. 但因为没有进行异常处理, 一旦运行时异常发生就会致使程序终止.
对运行时异常不采用抛出或捕获处理方式, 而是应该提早预判, 防止发生这种异常.

捕获异常

当前方法有能力解决时, 则捕获异常进行处理; 没有能力解决, 则抛给上层调用方法处理. 上层调用方法也无力解决时, 继续抛给它的上层调用方法. 若是全部方法都没有处理该异常, JVM 会终止程序运行.
try-catch 语句
语法格式:
try {   // 可能发生异常的语句
}catch(Throwable e) {   // 异常处理
}
try 代码块中包含可能发生异常的代码语句. 每一个 try 代码块能够伴随一个或多个 catch 代码块, 用于处理 try 代码块中可能发生的异常.
多个异常类之间存在父子关系时, 捕获异常顺序与 catch 代码块的顺序有关. 通常先捕获子类, 后捕获父类, 不然子类捕获不到.
多重捕获
Java 7 推出了多重捕获 (multi-catch) 技术, 在 catch 中多重捕获异经常使用 “|” 运算符链接.
try {   ... }catch(IOException | ParseException e) {   ... }

释放资源

有时在 try-catch 语句中会占用一些非 Java 资源. 为了确保这些资源能够释放, 可使用 finally 代码块或 Java 7 以后提供自动资源管理技术.
finally 代码块
try-catch 语句后面还能够跟一个 finally 代码块:
try {   ... }catch(Throwable e) {   ... }fianlly {   ... }
不管是否发生异常, finally 代码块都会执行.
自动资源管理
Java 7 以后提供了自动资源管理技术. 自动资源管理是在 try 语句上的扩展, 语法以下:
try(声明或初始化资源语句) {   ... }catch(Throwable e) {   ... }
在 try 语句后面追加声明或初始化资源语句, 能够有多条语句, 多条语句间使用分号 “;” 分隔.

throws 与声明方法抛出异常

方法后面声明抛出异常使用 “throws” 关键字. 多个异常间使用逗号 (,) 分隔.

自定义异常类

实现自定义异常类须要继承 Exception 类或其子类. 若是自定义运行时异常类须要继承 RuntimeException 类或其子类.
自定义异常类主要是提供两个构造方法:
public class MyException extends Exception {   public MyException{}   public MyException(String message)   {     super(message);   } }
throw 与显式抛出异常
throws 用于方法后声明抛出异常, throw 关键字用来人工引起异常.
throw new Exception("业务逻辑异常");
相关文章
相关标签/搜索