Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 268|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-12 17:08:24 | 显示全部楼层 |阅读模式
    函数式编程与面向对象编程的区别: 函数式编程将程序代码看做数学中的函数, 函数本身是另一个函数的函数或返回值, 即高阶函数.

    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("业务逻辑异常");
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-20 02:04 , Processed in 0.118302 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表