许多现代语言在语言级别支持模式匹配。 Java当前不支持模式匹配,但是希望将来会有所改变。
与示例的比较为开发人员提供了更灵活,更漂亮地编写代码的机会,同时使代码易于理解。
使用Java 8的功能,您可以库的形式实现模式匹配的某些功能。 在这种情况下,您可以同时使用语句和表达式。
常数模式允许检查常数是否相等。 在Java中,开关允许您检查是否有相等的数字,枚举和字符串。 但是有时候我想使用equals()方法检查对象常量是否相等。
switch (data) { case new Person("man") -> System.out.println("man"); case new Person("woman") -> System.out.println("woman"); case new Person("child") -> System.out.println("child"); case null -> System.out.println("Null value "); default -> System.out.println("Default value: " + data); };
对于不同的分支选项,您需要使用matches()方法的重载。 因此,目前,该库支持使用6个常量检查变量值的功能。
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.ConstantPattern.matches; matches(data, new Person("man"), () -> System.out.println("man"); new Person("woman"), () -> System.out.println("woman"); new Person("child"), () -> System.out.println("child"); Null.class, () -> System.out.println("Null value "), Else.class, () -> System.out.println("Default value: " + data) );
元组模式使您可以同时检查常量是否具有多个更改。
switch (side, width) { case "top", 25 -> System.out.println("top"); case "bottom", 30 -> System.out.println("bottom"); case "left", 15 -> System.out.println("left"); case "right", 15 -> System.out.println("right"); case null -> System.out.println("Null value "); default -> System.out.println("Default value "); };
目前,该库支持指定4个变量和6个分支的功能。
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.TuplePattern.matches; matches(side, width, "top", 25, () -> System.out.println("top"); "bottom", 30, () -> System.out.println("bottom"); "left", 15, () -> System.out.println("left"); "right", 15, () -> System.out.println("right"); Null.class, () -> System.out.println("Null value"), Else.class, () -> System.out.println("Default value") );
类型测试模式允许您同时匹配类型并提取变量的值。 在Java中,为此,我们需要首先检查类型,将其强制转换为类型,然后将其分配给新变量。
switch (data) { case Integer i -> System.out.println(i * i); case Byte b -> System.out.println(b * b); case Long l -> System.out.println(l * l); case String s -> System.out.println(s * s); case null -> System.out.println("Null value "); default -> System.out.println("Default value: " + data); };
目前,该库支持检查6种类型变量的值的功能。
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.VerifyPattern.matches; matches(data, Integer.class, i -> { System.out.println(i * i); }, Byte.class, b -> { System.out.println(b * b); }, Long.class, l -> { System.out.println(l * l); }, String.class, s -> { System.out.println(s * s); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
保护模式可让您同时匹配类型并检查条件。
switch (data) { case Integer i && i != 0 -> System.out.println(i * i); case Byte b && b > -1 -> System.out.println(b * b); case Long l && l < 5 -> System.out.println(l * l); case String s && !s.empty() -> System.out.println(s * s); case null -> System.out.println("Null value "); default -> System.out.println("Default: " + data); };
当前,该库支持使用6种类型和条件检查变量值的功能。
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.GuardPattern.matches; matches(data, Integer.class, i -> i != 0, i -> { System.out.println(i * i); }, Byte.class, b -> b > -1, b -> { System.out.println(b * b); }, Long.class, l -> l == 5, l -> { System.out.println(l * l); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
为了简化条件的编写,开发人员可以使用以下函数进行比较:lessThan / lt,GreaterThan / gt,lessThanOrEqual / le,GreaterThanOrEqual / ge,
等于/ eq,不等于/ ne。 为了忽略这些条件,您可以尝试:总是/是,从不/否。
matches(data, Integer.class, ne(0), i -> { System.out.println(i * i); }, Byte.class, gt(-1), b -> { System.out.println(b * b); }, Long.class, eq(5), l -> { System.out.println(l * l); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
解构模式允许您同时匹配类型并将对象分解为组件。 在Java中,为此,我们需要首先检查类型,将其转换为类型,将其分配给新变量,然后才通过getter访问类的字段。
let (int w, int h) = figure; switch (figure) { case Rectangle(int w, int h) -> out.println("square: " + (w * h)); case Circle(int r) -> out.println("square: " + (2 * Math.PI * r)); default -> out.println("Default square: " + 0); }; for ((int w, int h) : listFigures) { System.out.println("square: " + (w * h)); }
当前,该库支持检查3种类型的变量的值并将对象分解为3个成分的功能。
import org.kl.state.Else; import static org.kl.pattern.DeconstructPattern.matches; import static org.kl.pattern.DeconstructPattern.foreach; import static org.kl.pattern.DeconstructPattern.let; Figure figure = new Rectangle(); let(figure, (int w, int h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rectangle.class, (int w, int h) -> out.println("square: " + (w * h)), Circle.class, (int r) -> out.println("square: " + (2 * Math.PI * r)), Else.class, () -> out.println("Default square: " + 0) ); foreach(listRectangles, (int w, int h) -> { System.out.println("square: " + (w * h)); });
而且,为了获得组件,一个类必须具有一个或多个解构方法。 这些方法应标有“注释提取” 。
所有参数必须打开。 由于无法通过引用将基元传递给方法,因此您需要为基元IntRef,FloatRef等使用包装器。
import org.kl.type.IntRef; ... @Extract public void deconstruct(IntRef width, IntRef height) { width.set(this.width); height.set(this.height); }
同样使用Java 11,您可以推断出解构参数的类型。
Figure figure = new Rectangle(); let(figure, (var w, var h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rectangle.class, (var w, var h) -> out.println("square: " + (w * h)), Circle.class, (var r) -> out.println("square: " + (2 * Math.PI * r)), Else.class, () -> out.println("Default square: " + 0) ); foreach(listRectangles, (var w, var h) -> { System.out.println("square: " + (w * h)); });
通过属性模式 ,您可以同时匹配类型并通过其名称访问类的字段。 无需提供所有字段,而是可以按任何顺序访问所需的字段。
let (w: int w, h:int h) = figure; switch (figure) { case Rect(w: int w == 5, h: int h == 10) -> out.println("sqr: " + (w * h)); case Rect(w: int w == 10, h: int h == 15) -> out.println("sqr: " + (w * h)); case Circle (r: int r) -> out.println("sqr: " + (2 * Math.PI * r)); default -> out.println("Default sqr: " + 0); }; for ((w: int w, h: int h) : listRectangles) { System.out.println("square: " + (w * h)); }
目前,该库支持使用3种类型检查变量值并将对象分解为3个组件的功能。
import org.kl.state.Else; import static org.kl.pattern.PropertyPattern.matches; import static org.kl.pattern.PropertyPattern.foreach; import static org.kl.pattern.PropertyPattern.let; import static org.kl.pattern.PropertyPattern.of; Figure figure = new Rectangle(); let(figure, of("w", "h"), (int w, int h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rect.class, of("w", 5, "h", 10), (int w, int h) -> out.println("sqr: " + (w * h)), Rect.class, of("w", 10, "h", 15), (int w, int h) -> out.println("sqr: " + (w * h)), Circle.class, of("r"), (int r) -> out.println("sqr: " + (2 * Math.PI * r)), Else.class, () -> out.println("Default sqr: " + 0) ); foreach(listRectangles, of("x", "y"), (int w, int h) -> { System.out.println("square: " + (w * h)); });
您还可以使用另一种方法来简化命名字段。
Figure figure = new Rect(); let(figure, Rect::w, Rect::h, (int w, int h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rect.class, Rect::w, Rect::h, (int w, int h) -> out.println("sqr: " + (w * h)), Circle.class, Circle::r, (int r) -> out.println("sqr: " + (2 * Math.PI * r)), Else.class, () -> System.out.println("Default sqr: " + 0) ); foreach(listRectangles, Rect::w, Rect::h, (int w, int h) -> { System.out.println("square: " + (w * h)); });
位置模式可让您同时匹配类型并按声明顺序检查字段的值。 在Java中,为此,我们需要首先检查类型,将其转换为类型,将其分配给新变量,然后才通过getter访问类的字段并检查是否相等。
switch (data) { case Circle(5) -> System.out.println("small circle"); case Circle(15) -> System.out.println("middle circle"); case null -> System.out.println("Null value "); default -> System.out.println("Default value: " + data); };
目前,该库支持使用6种类型检查变量值并一次检查4个字段的功能。
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.PositionPattern.matches; import static org.kl.pattern.PositionPattern.of; matches(data, Circle.class, of(5), () -> { System.out.println("small circle"); }, Circle.class, of(15), () -> { System.out.println("middle circle"); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
另外,如果开发人员不想检查某些字段,则这些字段应标有@Exclude批注。 这些字段必须最后声明。
class Circle { private int radius; @Exclude private int temp; }
静态模式允许您同时匹配类型并使用工厂方法来解构对象。
Optional some = ...; switch (some) { case Optional.empty() -> System.out.println("empty value"); case Optional.of(var v) -> System.out.println("value: " + v); default -> System.out.println("Default value"); };
目前,该库支持检查6种类型的变量的值并将对象分解为3个部分的功能。
import org.kl.state.Else; import static org.kl.pattern.StaticPattern.matches; import static org.kl.pattern.StaticPattern.of; Optional some = ...; matches(figure, Optinal.class, of("empty"), () -> System.out.println("empty value"), Optinal.class, of("of") , (var v) -> System.out.println("value: " + v), Else.class, () -> System.out.println("Default value") );
同时,要获取组件,该类必须具有一个或多个标记为Extract批注的解构方法。
@Extract public void of(IntRef value) { value.set(this.value); }
序列模式使处理数据序列更加容易。
List<Integer> list = ...; switch (list) { case Ranges.head(var h) -> System.out.println("list head: " + h); case Ranges.tail(var t) -> System.out.println("list tail: " + t); case Ranges.empty() -> System.out.println("Empty value"); default -> System.out.println("Default value"); };
使用该库,您可以编写如下内容。
import org.kl.state.Else; import org.kl.range.Ranges; import static org.kl.pattern.SequencePattern.matches; List<Integer> list = ...; matches(figure, Ranges.head(), (var h) -> System.out.println("list head: " + h), Ranges.tail(), (var t) -> System.out.println("list tail: " + t), Ranges.empty() () -> System.out.println("Empty value"), Else.class, () -> System.out.println("Default value") );
另外,为简化代码,您可以使用以下功能。
import static org.kl.pattern.CommonPattern.with; import static org.kl.pattern.CommonPattern.when; Rectangle rect = new Rectangle(); with(rect, it -> { it.setWidth(5); it.setHeight(10); }); when( side == Side.LEFT, () -> System.out.println("left value"), side == Side.RIGHT, () -> System.out.println("right value") );
如您所见,模式匹配是一个功能强大的工具,可简化代码编写。 使用lambda表达式,方法引用和lambda参数类型的派生,您可以通过语言工具来模拟模式匹配的可能性。
该库的源代码是开放的,可以在github上找到 。