使用注释创建Callables

我正在尝试建立一个类似于https://github.com/ElgarL/TownyChat/blob/master/src/com/palmergames/bukkit/TownyChat/TownyChatFormatter.java的系统

replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() { @Override public String call(String match, LocalTownyChatEvent event) throws Exception { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); } }); replacer.registerFormatReplacement(Pattern.quote("{town}"), new TownyChatReplacerCallable() { @Override public String call(String match, LocalTownyChatEvent event) throws Exception { return event.getResident().hasTown() ? event.getResident().getTown().getName() : ""; } }); 

和更多。

有没有办法使用注释来减少重复代码的数量,避免reflection调用调用方法,并且只在注册时使用它,如果有的话?

我并不反对创建注释预处理器的想法,因为我已经计划这样做以启用自动生成文档。

我们假设您编写了一个小注释

 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface PatternHandler { String value(); } 

并创建一个类

 class Callables { @PatternHandler("foo") public static final TownyChatReplacerCallable FOO = new TownyChatReplacerCallable() { @Override public String call(String match, String event) { return "This is foo handler called with " + match + "," + event; } }; @PatternHandler("bar") public static final TownyChatReplacerCallable BAR = new TownyChatReplacerCallable() { @Override public String call(String match, String event) { return "This is foo handler called with " + match + "," + event; } }; } 

现在,您可以获取整个类甚至包含这些静态字段的多个类,并将其传递给某个注册表方法,该方法反复迭代该类中的每个字段,如果它是带注释的可调用寄存器。

 class AnnotationRegistry { public static void register(String pattern, TownyChatReplacerCallable handler) {} public static void register(Class clazz) { // only fields declared by this class, not inherited ones (static fields can't be inherited) Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // must have that annotation PatternHandler annotation = field.getAnnotation(PatternHandler.class); if (annotation != null) { // must be static if (!Modifier.isStatic(field.getModifiers())) { System.out.println("Field must be static:" + field.getName()); continue; } // get content of that field try { Object object = field.get(null); // must be != null and a callable if (object instanceof TownyChatReplacerCallable) { register(annotation.value(), (TownyChatReplacerCallable) object); } else { System.out.println("Field must be instanceof TownyChatReplacerCallable:" + field.getName()); } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } 

这样可以节省一些代码,并且在运行时没有速度劣势,因为不需要使用reflection来调用那些callables。

这里有完整的例子: http : //ideone.com/m3PPcY

除了使用静态字段之外,如果将类的实例传递给注册表,也可以使用非静态字段,然后将其用作Object object = field.get(instance); 而不是null

此外,代替字段,相同的方法将适用于编写代码较少的方法:

 @PatternHandler("foo") public static String fooMethod(String match, String event) { return "This is foo handler called with " + match + "," + event; } 

然后,注册表将查找所有Method 。 然后例如将它们包裹起来

 class MethodAdapter implements TownyChatReplacerCallable { private final Method method; public MethodAdapter(Method m) { method = m; } @Override public String call(String match, String event) { try { return (String) method.invoke(null, match, event); } catch (Exception e) { e.printStackTrace(); return "OMGZ"; } } } 

并照常继续。 但要注意:reflection调用方法可能比通过代码直接调用它更慢 – 只有几个百分点,没有什么可担心的

方法的完整示例: http : //ideone.com/lMJsrl

您可以尝试使用新的Java 8 Lambda表达式( http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html )。

 replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() { @Override public String call(String match, LocalTownyChatEvent event) throws Exception { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); } }); 

可以写成:

 replacer.registerFormatReplacement( Pattern.quote("{worldname}"), (match, event) -> { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); } }); 

您还可以使用另一个接口,方法…来进一步推送它