前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我在jdk8实现了jdk18的新特性

我在jdk8实现了jdk18的新特性

作者头像
阿超
发布2022-08-21 12:53:29
3730
发布2022-08-21 12:53:29
举报
文章被收录于专栏:快乐阿超快乐阿超

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

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

代码语言:javascript
复制
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版本

代码语言:javascript
复制
/**
 * 通过对象的方法或类的静态方法引用,然后根据{@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, ';')));
}

接下来是用法

代码语言:javascript
复制
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());

	}


}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档