类型匹配

在 JDK 14 中以预览版的形式发布。在 JDK 15 中,改进的类型匹配再次以预览版的形式发布。最后,类型匹配在 JDK 16 正式发布。

类型匹配主要是用于优化instanceof强制类型转换的情况。

语法

对象值 instanceof 对象类型 比对成功赋值给的对象

以前写法:

public BmwCar bmwCar(Car car){
  if (car instanceof BmwCar) {
    return (BmwCar) car;
  }
  return null;
}

类型匹配写法:

public BmwCar bmwCar2(Car car){
  if (car instanceof BmwCar bmwCar) {
    return bmwCar;
  }
  return null;
}

这样写的优点: 可以简化我们类型强转可能会带来的错误,由内部判断,如果属于,则自动将后面的值转换为匹配类型。

作用域

  1. 1. 匹配情况
if (car instanceof BmwCar bmwCar) {
    // bmwCar能使用的范围
}
// bmwCar不能使用
  1. 1. 不匹配情况
  • • 只有if的情况:
if (!(car instanceof BmwCar bmwCar)) {
    // bmwCar不能使用
}
// bmwCar能使用的范围
  • • 有if(){}else(){}的情况
if (!(car instanceof BmwCar bmwCar)) {
    // bmwCar不能使用
} else {
    // bmwCar能使用的范围
}
// bmwCar能使用的范围
  1. 1. 逻辑运算符
  • • &&情况,可以直接使用再&&后面用于判断
if (car instanceof BmwCar bmwCar && bmwCar.tire() == "米其林"){}
  • • ||情况,不可以使用在||后面
  • • 因为||只要前面不满足就没必要使用转换后的值进行判断(类型不匹配转换肯定不成功)
  • • 前面满足就是true,那么也不会去判断后面

优点

  • • 降低我们类型匹配后再强转的出错率
  • • 提高了代码转换的效率

Switch 表达式

在 JDK 12 中以预览版的形式发布。在 JDK 13 中,改进的 switch 表达式再次以预览版的形式发布。最后,switch 表达式在 JDK 14 正式发布。

Switch表达式

以前写法:

public String switchDemo(Integer state) {
  String desc;
  switch (state) {
    case 1:
    case 2:
    case 3:
      desc = "进入1,2,3语句";
      break;
    case 4:
      desc = "4语句";
      break;
    case 5:
    case 6:
      if (state % 2 == 0) {
        desc = "进入5,6语句且不能被2整除";
      } else {
        desc = "进入5,6语句且能被2整除";
      }
      break;
    default:
      throw new IllegalStateException();
  }
  return desc;
}

优化写法:

public String switchDemo(Integer state) {
  return switch (state) {
    case 1, 2, 3 -> "进入1,2,3语句";
    case 4 -> "4语句";
    case 5, 6 -> {
      if (state % 2 == 0) {
        yield "进入5,6语句且不能被2整除";
      } else {
        yield "进入5,6语句且能被2整除";
      }
    }
    default -> throw new IllegalStateException();
  };
}

变动情况:

  • • 和之前的switch语句不同,这个switch是一个表达式(有返回值)
  • • 一个case语句后面可以跟多个匹配项
  • • 标识符由:变为->
  • • 箭头右侧的值表示表达式匹配的情况下,switch表达式的值
  • • 箭头右侧是代码块的情况,由yield关键字指明switch表达式的值

注意:

  • • yield关键字只能使用在switch表达式的代码块中,如果不是代码块直接返回会报错// 编译会报错
    case 4 -> yield "4语句";
  • • switch 表达式里,必须要将所有情况列举出来,不能多、也不能少public String switchDemo(Integer state) {
      return switch (state) {
        case 123 -> "进入1,2,3语句";
        case 4 -> "4语句";
        case 56 -> {
          if (state % 2 == 0) {
            yield "进入5,6语句且不能被2整除";
          } else {
            yield "进入5,6语句且能被2整除";
          }
        }
        // 如果注释了default那么编译就会报错
        // default -> throw new IllegalStateException();
      };
    }
  • • 不能在case语句块中使用return、breakcase 56 -> {
      if (state % 2 == 0) {
        // 会报错
        //return;
        break;
      } 
      yield "进入5,6语句且能被2整除";
    }

Switch 语句

和表达式一样也做了对应的改进

public void switchDemo2(Integer state) {
  switch (state) {
    case 1, 2, 3 -> System.out.println("进入1,2,3语句");
    case 4 -> System.out.println("4语句");
    case 5, 6 -> {
      if (state % 2 == 0) {
        System.out.println("进入5,6语句且不能被2整除");
        break;
      }
      System.out.println("进入5,6语句且能被2整除");
    }
    default -> throw new IllegalStateException();
  }
}

与Switch表达式不同点:

  • • 语句块里面不能使用yield
  • • 可以在case后面语句块中使用return、break关键字
  • • 可以不用列出所有情况,比如上面将default注释了也没问题

switch匹配(特性未定稿)

switch 的模式匹配这个特性,在 JDK 17 中以预览版的形式发布。

JDK 17 之前的 switch 关键字可以匹配的数据类型包括数字、枚举和字符串。switch匹配用于匹配对象(引用数据类型)

如下:

public static boolean isFileStream(InputStream in){
  return switch (in) {
    case FileInputStream f-> true;
    case ByteArrayInputStream b-> false;
    case null,default -> false;
  };
}

特点:

  • • 支持 null 匹配
  • • 不会像之前传入null会报空指针异常
  • • case后面的对象类型后面跟着一个定义(如:FileInputStream f中的f),这个是匹配后转换的数据类型,在->后面可以使用f.fun()来使用对应的方法
  • • case必须包含全部的业务场景,如果囊括不完的也要使用default表示,否则编译会报错
  • • 改进后的switch(包括 switch 语句和 switch 表达式),比if(){}else(){}的性能更好

注意:

public static boolean isFileStream(InputStream in){
  return switch (in) {
    case FileInputStream f-> true;
    case ByteArrayInputStream b-> false;
    // 由于上面的case已经返回false,而且下面的case已经包含了上面的,所以下面的情况会报错
    // case ByteArrayInputStream b && 1 == 1-> false;
    case null,default -> false;
  };
}