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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
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版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 通过对象的方法或类的静态方法引用,然后根据{@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, ';')));
}

接下来是用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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());

}


}