我在jdk8实现了jdk18的新特性

简介: 我在jdk8实现了jdk18的新特性

在自己身上,克服这个时代。——尼采

首先放jdk18的官方特性介绍地址:https://openjdk.java.net/jeps/420

我就不再过多解释了,直接贴代码吧~

package cn.hutool.core.lang;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.lang.func.VoidFunc1;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
 * 在不考虑性能的前提下,尽可能实现 JEP 420: Pattern Matching for switch,这是jdk18即将发布的新特性的变种写法
 * 类型转换 instanceOf 老写法如下:
 * <pre>{@code
 *  public static String formatter(Object o) {
 *    String formatted = "unknown";
 *    if (o instanceof Integer) {
 *      Integer i = (Integer) o;
 *      formatted = String.format("int %d", i);
 *                } else if (o instanceof Long) {
 *      Long l = (Long) o;
 *      formatted = String.format("long %d", l);
 *        } else if (o instanceof Double) {
 *      Double d = (Double) o;
 *      formatted = String.format("double %f", d);
 *        } else if (o instanceof String) {
 *      String s = (String) o;
 *      formatted = String.format("String %s", s);
 *        }
 *    return formatted;
 * }
 * }</pre>
 * {@link SwitchCase}用法为
 * <pre>{@code
 * static String formatterWithSwitchCase(Object o) {
 *    return SwitchCase.choose(o)
 *        .when((Integer i) -> String.format("int %d", i))
 *        .when((Long l) -> String.format("long %d", l))
 *        .when((Double d) -> String.format("double %f", d))
 *        .when((String s) -> String.format("String %s", s))
 *        .otherwise("unknown")
 *        .get();
 *        }
 * }</pre>
 * 然后对于一般条件且无返回值的情况:
 * <pre>{@code
 * SwitchCase.choose(str)
 *        .whenConsumer(s -> System.out.println("Oops"), null)
 *        .whenConsumer(s -> System.out.println("Great"), "Foo", "Bar")
 *        .otherwiseConsumer(s -> System.out.println("Ok"));
 * }</pre>
 *
 * @author VampireAchao
 * @since 2022/3/26 15:56
 */
@SuppressWarnings("unchecked")
public class SwitchCase<T> {
  private final T source;
  private boolean isMatched = false;
  private boolean isDefault = false;
  private final Class<T> type;
  private SwitchCase(T source) {
    this.source = source;
    this.type = source == null ? null : (Class<T>) source.getClass();
  }
  private SwitchCase(T source, boolean isMatched) {
    this.source = source;
    this.isMatched = isMatched;
    this.type = source == null ? null : (Class<T>) source.getClass();
  }
  private SwitchCase(T source, boolean isMatched, boolean isDefault) {
    this.source = source;
    this.isMatched = isMatched;
    this.isDefault = isDefault;
    this.type = source == null ? null : (Class<T>) source.getClass();
  }
  public T get() {
    return source;
  }
  public boolean isMatched() {
    return isMatched;
  }
  public boolean isDefault() {
    return isDefault;
  }
  public Class<T> getType() {
    return type;
  }
  public static <T> SwitchCase<T> choose(T obj) {
    return new SwitchCase<>(obj);
  }
  /**
   * 传入lambda,根据类型自动完成匹配
   *
   * @param function lambda,例如 {@code (Integer i) -> String.format("int %d", i)}
   * @param <S>      lambda指定的参数类型
   * @param <R>      lambda指定的返回值类型
   * @param <O>      实际的类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <S, R, O> SwitchCase<O> when(Func1<S, R> function) {
    if (false == isMatched && LambdaUtil.getRealClass(function).isInstance(source)) {
      return new SwitchCase<>((O) function.callWithRuntimeException((S) source), true);
    }
    return (SwitchCase<O>) this;
  }
  /**
   * 传入lambda,根据类型自动完成匹配
   *
   * @param consumer lambda,例如 {@code (Integer i) -> Console.log("int {}", i)}
   * @param <S>      lambda指定的参数类型
   * @param <O>      实际的类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <S, O> SwitchCase<O> whenConsumer(VoidFunc1<S> consumer) {
    if (false == isMatched && LambdaUtil.getRealClassConsumer(consumer).isInstance(source)) {
      consumer.callWithRuntimeException((S) source);
      return new SwitchCase<>((O) source, true);
    }
    return (SwitchCase<O>) this;
  }
  /**
   * 传入lambda,根据条件自动完成匹配
   *
   * @param condition 可传入条件表达式,例如{@code v -> ObjectUtil.isNotNull(v) && "hutool".equals(v)}
   * @param function  需要进行的操作
   * @param <R>       操作返回值
   * @param <O>       实际的类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <R, O> SwitchCase<O> when(Predicate<T> condition, Function<T, R> function) {
    if (false == isMatched && condition.test(source)) {
      return new SwitchCase<>((O) function.apply(source), true);
    }
    return (SwitchCase<O>) this;
  }
  /**
   * 传入lambda,根据条件自动完成匹配
   *
   * @param compare  比较的值
   * @param function 需要进行的操作
   * @param <R>      操作返回值
   * @param <O>      实际的类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <R, O> SwitchCase<O> when(T compare, Function<T, R> function) {
    return when(function, compare);
  }
  /**
   * 传入lambda,根据条件自动完成匹配,由于动态参数只能放在最后,不得不调整下参数顺序
   *
   * @param function 需要进行的操作
   * @param compares 需要匹配的参数
   * @param <R>      操作返回值
   * @param <O>      实际的类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <R, O> SwitchCase<O> when(Function<T, R> function, T... compares) {
    if (false == isMatched && Arrays.asList(compares).contains(source)) {
      return new SwitchCase<>((O) function.apply(source), true);
    }
    return (SwitchCase<O>) this;
  }
  /**
   * 传入lambda,根据条件自动完成匹配,由于动态参数只能放在最后,不得不调整下参数顺序
   *
   * @param consumer 需要进行的操作
   * @param compares 需要匹配的参数
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public SwitchCase<T> whenConsumer(Consumer<T> consumer, T... compares) {
    if (false == isMatched
        && (compares == null && source == null)
        || (compares != null && Arrays.asList(compares).contains(source))) {
      consumer.accept(source);
      return new SwitchCase<>(source, true);
    }
    return this;
  }
  /**
   * 传入lambda,根据条件自动完成匹配
   *
   * @param condition 可传入条件表达式,例如{@code v -> ObjectUtil.isNotNull(v) && "hutool".equals(v)}
   * @param consumer  需要进行的操作
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public SwitchCase<T> whenPredicateConsumer(Predicate<T> condition, Consumer<T> consumer) {
    if (false == isMatched && condition.test(source)) {
      consumer.accept(source);
      return new SwitchCase<>(source, true);
    }
    return this;
  }
  /**
   * 如果其他条件不满足,则执行
   *
   * @param function 想要执行的lambda
   * @param <O>      返回值类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <O> SwitchCase<O> otherwise(UnaryOperator<O> function) {
    if (false == isMatched) {
      return new SwitchCase<>(function.apply((O) source), false, true);
    }
    return (SwitchCase<O>) this;
  }
  /**
   * 如果其他条件不满足,则提供该默认值
   *
   * @param value 默认值
   * @param <O>   返回值类型
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public <O> SwitchCase<O> otherwise(O value) {
    if (false == isMatched) {
      return new SwitchCase<>(value, false, true);
    }
    return (SwitchCase<O>) this;
  }
  /**
   * 如果其他条件不满足,则执行
   *
   * @param consumer 想要执行的lambda
   * @return 匹配后封装的 {@link SwitchCase}
   */
  public SwitchCase<T> otherwiseConsumer(Consumer<T> consumer) {
    if (false == isMatched) {
      consumer.accept(source);
      return new SwitchCase<>(source, false, true);
    }
    return this;
  }
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof SwitchCase)) {
      return false;
    }
    return Objects.equals(((SwitchCase<?>) o).get(), source);
  }
  @Override
  public String toString() {
    return String.valueOf(source);
  }
}


然后其中用到了LambdaUtil,自己额外新增了一个方法,其余的在hutool5.8版本

/**
 * 通过对象的方法或类的静态方法引用,然后根据{@link SerializedLambda#getInstantiatedMethodType()}获取lambda实现类<br>
 * 传入lambda有参数且无返回值的情况能够匹配到此方法:
 *
 * @param func lambda
 * @param <P>  方法调用方类型
 * @return lambda实现类
 * @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
 */
public static <P> Class<P> getRealClassConsumer(VoidFunc1<P> func) {
  SerializedLambda lambda = _resolve(func);
  checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
  String instantiatedMethodType = lambda.getInstantiatedMethodType();
  return ClassUtil.loadClass(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')));
}

接下来是用法

package cn.hutool.core.lang;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.junit.Assert;
import org.junit.Test;
/**
 * SwitchCaseTest
 *
 * @author VampireAchao
 * @since 2022/3/26 15:57
 */
public class SwitchCaseTest {
  /**
   * 老写法
   */
  public static String formatter(Object o) {
    String formatted = "unknown";
    if (o instanceof Integer) {
      Integer i = (Integer) o;
      formatted = String.format("int %d", i);
    } else if (o instanceof Long) {
      Long l = (Long) o;
      formatted = String.format("long %d", l);
    } else if (o instanceof Double) {
      Double d = (Double) o;
      formatted = String.format("double %f", d);
    } else if (o instanceof String) {
      String s = (String) o;
      formatted = String.format("String %s", s);
    }
    return formatted;
  }
  /**
   * 新写法,{@see https://openjdk.java.net/jeps/420}
   */
  public static String formatterWithSwitchCase(Object o) {
    return SwitchCase.choose(o)
        .when((Integer i) -> String.format("int %d", i))
        .when((Long l) -> String.format("long %d", l))
        .when((Double d) -> String.format("double %f", d))
        .when((String s) -> String.format("String %s", s))
        .otherwise("unknown")
        .get();
  }
  public static void formatterWithSwitchCaseConsumer(Object o) {
    SwitchCase.choose(o)
        .whenConsumer((Integer i) -> Console.log("int {}", i))
        .whenConsumer((Long l) -> Console.log("long {}", l))
        .whenConsumer((Double d) -> Console.log("double {}", d))
        .whenConsumer((String s) -> Console.log("String {}", s))
        .otherwise(s -> "unknown")
        .get();
  }
  static void testFooBar(String str) {
    /*switch (s) {
      case null -> System.out.println("Oops");
      case "Foo", "Bar" -> System.out.println("Great");
      default -> System.out.println("Ok");
    }*/
    SwitchCase.choose(str)
        .whenConsumer(s -> System.out.println("Oops"), null)
        .whenConsumer(s -> System.out.println("Great"), "Foo", "Bar")
        .otherwiseConsumer(s -> System.out.println("Ok"));
  }
  @Test
  public void testWhenConsumer() {
    testFooBar(null);
    testFooBar("Foo");
    testFooBar("");
  }
  @Test
  public void whenTest() {
    Assert.assertTrue(SwitchCase.choose(Class.class).when((Class<?> cls) -> cls).isMatched());
    Assert.assertFalse(SwitchCase.choose(0).when((String s) -> s).isMatched());
    Assert.assertTrue(SwitchCase.choose(Class.class).whenConsumer((Class<?> cls) -> Console.log()).isMatched());
    Assert.assertFalse(SwitchCase.choose(0).whenConsumer((String s) -> Console.log()).isMatched());
    Assert.assertTrue(SwitchCase.choose("ruben").when("x", s -> s).otherwise(s -> s).isDefault());
    Assert.assertFalse(SwitchCase.choose("ruben").when("ruben", s -> s).isDefault());
    Assert.assertEquals("Feature",
        SwitchCase.choose("hutool")
            .when(
                // 条件
                v -> ObjectUtil.isNotNull(v) && "hutool".equals(v),
                // 实际操作
                s -> "Feature"
            ).get());
  }
}
相关文章
|
8月前
|
Java 测试技术 调度
JDK21有没有什么稳定、简单又强势的特性?
这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。
JDK21有没有什么稳定、简单又强势的特性?
|
11月前
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
155 7
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
195 1
|
Java 关系型数据库 开发工具
idea创建不了spring2.X版本,无法使用JDK8,最低支持JDK17 , 如何用idea创建spring2.X版本,使用JDK8解决方案
本文提供了解决方案,如何在IDEA中创建Spring 2.X版本的项目并使用JDK8,尽管Spring 2.X已停止维护且IDEA不再直接支持,通过修改pom.xml或使用阿里云的国内源来创建项目。
1244 0
idea创建不了spring2.X版本,无法使用JDK8,最低支持JDK17 , 如何用idea创建spring2.X版本,使用JDK8解决方案
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
133 3
|
存储 安全 Java
JDK1.8 新的特性
JDK1.8 新的特性
147 0
|
Oracle Java 关系型数据库
jdk17安装全方位手把手安装教程 / 已有jdk8了,安装JDK17后如何配置环境变量 / 多个不同版本的JDK,如何配置环境变量?
本文提供了详细的JDK 17安装教程,包括下载、安装、配置环境变量的步骤,并解释了在已有其他版本JDK的情况下如何管理多个JDK环境。
19114 0
|
编解码 安全 Java
jdk8新特性-接口和日期处理
jdk8新特性-接口和日期处理
|
Java 编译器 API
JDK8新特性--lambda表达式
JDK8的Lambda表达式是Java语言的一大进步。它为Java程序提供了更多的编程方式,让代码更加简洁,也让函数式编程的概念在Java中得到了体现。Lambda表达式与Java 8的其他新特性,如Stream API、新的日期时间API一起,极大地提高了Java编程的效率和乐趣。随着时间的流逝,Java开发者对这些特性的理解和应用将会越来越深入,进一步推动Java语言和应用程序的发展。
96 0
|
4月前
|
存储 Ubuntu 安全
在Ubuntu 16.04上安装openjdk-6/7/8-jdk的步骤
在整个安装过程中,你可能需要管理员权限,因此你可能要使用 `sudo` 来获取必要的权限。记得做完每一个步骤后,都要检查输出,以确保没有发生错误,并且每项操作都成功完成。如果在安装过程中遇到问题,查看 `/var/log/` 下的日志文件对于问题的解决可能是有帮助的。
239 21