Menerapkan pencocokan pola di Jawa

Banyak bahasa modern mendukung pencocokan pola di tingkat bahasa. Java saat ini tidak mendukung pencocokan pola, tetapi ada harapan bahwa beberapa hal dapat berubah di masa depan.


Perbandingan dengan sampel menunjukkan kepada pengembang kesempatan untuk menulis kode lebih fleksibel dan lebih indah, sambil tetap dimengerti.


Menggunakan kemampuan Java 8, Anda dapat mengimplementasikan beberapa fitur pencocokan pola dalam bentuk perpustakaan. Dalam hal ini, Anda bisa menggunakan pernyataan dan ekspresi.


Pola konstan memungkinkan memeriksa kesetaraan dengan konstanta. Di Jawa, sebuah sakelar memungkinkan Anda memeriksa angka, enumerasi, dan string yang sama. Tapi kadang-kadang saya ingin memeriksa persamaan konstanta objek menggunakan metode 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); }; 

Untuk opsi percabangan yang berbeda, Anda perlu menggunakan metode pencocokan () yang berlebihan. Oleh karena itu, saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 6 konstanta.


 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) ); 

Pola Tuple memungkinkan Anda untuk memeriksa kesetaraan beberapa perubahan dengan konstanta secara bersamaan.


 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 "); }; 

Saat ini, perpustakaan mendukung kemampuan untuk menentukan 4 variabel dan 6 cabang.


 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") ); 

Pola uji tipe memungkinkan Anda untuk secara bersamaan mencocokkan jenis dan mengekstraksi nilai variabel. Di Jawa, untuk ini kita perlu memeriksa jenisnya terlebih dahulu, melemparkan ke jenis dan kemudian menetapkannya ke variabel baru.


 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); }; 

Saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 6 jenis.


 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); } ); 

Pola pelindung memungkinkan Anda untuk secara bersamaan mencocokkan jenis dan memeriksa kondisi.


 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); }; 

Saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 6 jenis dan kondisi.


 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); } ); 

Untuk menyederhanakan penulisan kondisi, pengembang dapat menggunakan fungsi-fungsi berikut untuk perbandingan: lessThan / lt, GreaterThan / gt, lessThanOrEqual / le, GreaterThanOrEqual / ge,
sama / sama, tidak sama / ne. Dan untuk menghilangkan persyaratan, Anda dapat mencoba: selalu / ya, tidak pernah / tidak.


 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); } ); 

Pola dekonstruksi memungkinkan Anda untuk secara bersamaan mencocokkan jenis dan menguraikan objek menjadi komponen. Di Jawa, untuk ini kita perlu memeriksa jenisnya, melemparkan ke suatu jenis, menetapkannya ke variabel baru, dan hanya kemudian mengakses bidang kelas melalui 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)); } 

Saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 3 jenis dan menguraikan objek menjadi 3 komponen.


 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)); }); 

Selain itu, untuk mendapatkan komponen, kelas harus memiliki satu atau lebih metode mendekonstruksi. Metode ini harus diberi label dengan Annotation Extract .
Semua parameter harus terbuka. Karena primitif tidak dapat diteruskan ke metode dengan referensi, Anda perlu menggunakan pembungkus untuk primitif IntRef, FloatRef, dll.


 import org.kl.type.IntRef; ... @Extract public void deconstruct(IntRef width, IntRef height) { width.set(this.width); height.set(this.height); } 

Juga menggunakan Java 11, Anda dapat menyimpulkan tipe-tipe parameter dekonstruksi.


 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)); }); 

Pola properti memungkinkan Anda untuk secara bersamaan mencocokkan jenis dan mengakses bidang kelas dengan nama mereka. Alih-alih menyediakan semua bidang, Anda dapat mengakses bidang yang Anda butuhkan dalam urutan apa pun.


 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)); } 

Saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 3 jenis dan menguraikan objek menjadi 3 komponen.


 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)); }); 

Anda juga dapat menggunakan metode lain untuk menyederhanakan bidang penamaan.


 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)); }); 

Pola posisi memungkinkan Anda untuk secara bersamaan mencocokkan jenis dan memeriksa nilai bidang dalam urutan deklarasi. Di Jawa, untuk ini kita perlu memeriksa jenisnya, melemparkannya ke suatu jenis, menetapkannya ke variabel baru, dan hanya kemudian mengakses bidang kelas melalui getter dan memeriksa kesetaraan.


 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); }; 

Saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 6 jenis dan memeriksa 4 bidang sekaligus.


 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); } ); 

Selain itu, jika pengembang tidak ingin memeriksa beberapa bidang, bidang ini harus ditandai dengan anotasi @Kecualikan. Bidang-bidang ini harus dinyatakan terakhir.


 class Circle { private int radius; @Exclude private int temp; } 

Pola statis memungkinkan Anda untuk secara bersamaan mencocokkan jenis dan mendekonstruksi objek menggunakan metode pabrik.


 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"); }; 

Saat ini, perpustakaan mendukung kemampuan untuk memeriksa nilai-nilai variabel dengan 6 jenis dan menguraikan objek menjadi 3 komponen.


 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") ); 

Pada saat yang sama, untuk mendapatkan komponen, kelas harus memiliki satu atau lebih metode mendekonstruksi, berlabel anotasi Ekstrak .


 @Extract public void of(IntRef value) { value.set(this.value); } 

Pola urutan membuatnya lebih mudah untuk memproses urutan data.


 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"); }; 

Menggunakan perpustakaan, Anda dapat menulis sebagai berikut.


 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") ); 

Juga, untuk menyederhanakan kode, Anda dapat menggunakan fungsi berikut.


 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") ); 

Seperti yang Anda lihat pencocokan pola adalah alat yang ampuh yang membuat penulisan kode jauh lebih mudah. Menggunakan ekspresi lambda, referensi metode, dan derivasi jenis parameter lambda, Anda dapat meniru kemungkinan pencocokan pola dengan alat yang sangat bahasa.


Kode sumber perpustakaan terbuka dan tersedia di github .

Source: https://habr.com/ru/post/id460773/


All Articles