Javaでコレクションクロージャメソッドっぽいこと
Rubyのselectとかcollectみたいなものって、Javaでも匿名クラスで一応実現できるけど、それだとどうしても冗長になります。
クロージャの部分にLLの力を借りたらすっきりするかなと思って、Java+Groovy版のコレクションクロージャメソッドを書いてみました。JRuby版とかRhino版も同様に作れると思います。
- Groovy.java
package test; import groovy.lang.Binding; import groovy.lang.GroovyShell; import groovy.lang.Script; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class Groovy { private static Map<String, Script> cache = new HashMap<String, Script>(); private static Object eval(String expr, Binding binding) { Script script = cache.get(expr); if (script == null) { GroovyShell shell = new GroovyShell(); script = shell.parse(expr); cache.put(expr, script); } script.setBinding(binding); return script.run(); } private static Binding createBinding(Collection<?> c) { return new Binding(Collections.singletonMap("c", c)); } public static <T, S> Collection<S> collect(Collection<T> c, String expr, Class<S> resultClass) { return (Collection<S>) eval("c.collect { " + expr + " }", createBinding(c)); } public static <T> Collection<T> collect(Collection<T> c, String expr) { return (Collection<T>) eval("c.collect { " + expr + " }", createBinding(c)); } public static <T> T find(Collection<T> c, String expr) { return (T) eval("c.find { " + expr + " }", createBinding(c)); } public static <T> Collection<T> findAll(Collection<T> c, String expr) { return (Collection<T>) eval("c.findAll { " + expr + " }", createBinding(c)); } public static boolean every(Collection<?> c, String expr) { return (Boolean) eval("c.every { " + expr + " }", createBinding(c)); } public static boolean any(Collection<?> c, String expr) { return (Boolean) eval("c.any { " + expr + " }", createBinding(c)); } public static <T> T min(Collection<T> c, String expr) { return (T) eval("c.min { " + expr + " }", createBinding(c)); } public static <T> T max(Collection<T> c, String expr) { return (T) eval("c.max { " + expr + " }", createBinding(c)); } }
以下のようにして使います。
- Test.java
package test; import java.util.Arrays; import java.util.List; import static test.Groovy.*; public class Test { public static void main(String[] args) { List<String> list = Arrays.asList( "C#", "Java", "JavaScript", "Python", "Ruby", "Scala"); System.out.println("collect : " + collect(list, "it.toUpperCase()")); System.out.println("find : " + find (list, "it.startsWith('Java')")); System.out.println("findAll : " + findAll(list, "it.startsWith('Java')")); System.out.println("every : " + every (list, "it.matches('[A-Za-z]+')")); System.out.println("any : " + any (list, "it.contains('#')")); System.out.println("min : " + min (list, "it.length()")); System.out.println("max : " + max (list, "it.length()")); } }
実行結果は次のようになります。
collect : [C#, JAVA, JAVASCRIPT, PYTHON, RUBY, SCALA] find : Java findAll : [Java, JavaScript] every : false any : true min : C# max : JavaScript
ちょっとした用途になら使えるかも。