
翻蚳è
ããïŒLambdaMetafactoryã¯ãããããæãéå°è©äŸ¡ãããŠããJava 8ã¡ã«ããºã ã®1ã€ã§ãããæè¿çºèŠããŸãããããã§ã«ãã®æ©èœãé«ãè©äŸ¡ããŠããŸãã CUBAãã¬ãŒã ã¯ãŒã¯ã®ããŒãžã§ã³7.0ã§ã¯ãã©ã ãåŒã®çæãåªå
ããŠãªãã¬ã¯ã·ã§ã³ã³ãŒã«ãåé¿ããããšã«ãããããã©ãŒãã³ã¹ãåäžããŠããŸãã ãã¬ãŒã ã¯ãŒã¯ã«ããããã®ã¡ã«ããºã ã®ã¢ããªã±ãŒã·ã§ã³ã®1ã€ã¯ãSpringã®EventListenerã®é¡äŒŒç©ã§ããã¢ãããŒã·ã§ã³ãå
±éã¿ã¹ã¯ã«ããã¢ããªã±ãŒã·ã§ã³ã€ãã³ããã³ãã©ãŒã®ãã€ã³ãã§ãã LambdaFactoryã®ååã«é¢ããç¥èã¯å€ãã®Javaã¢ããªã±ãŒã·ã§ã³ã§åœ¹ç«ã€ãšä¿¡ããŠããããã®ç¿»èš³ãæ¥ãã§å
±æããŸãã
ãã®èšäºã§ã¯ãJava 8ã§ã©ã ãåŒã䜿çšããéã®ããŸãç¥ãããŠããªãããªãã¯ãšããããã®åŒã®å¶éã瀺ããŸãã ãã®èšäºã®å¯Ÿè±¡èªè
ã¯ãã·ãã¢Javaéçºè
ãç ç©¶è
ãããŒã«ãããéçºè
ã§ãã ãããªãã¯Java APIã®ã¿ãcom.sun.*
ãªãã§äœ¿çšããcom.sun.*
ãŸããä»ã®å
éšã¯ã©ã¹ã®ãããã³ãŒãã¯ç°ãªãJVMå®è£
éã§ç§»æ€å¯èœã§ãã
çãåºæ
Java 8ã§ã¯ãå¿åã¡ãœãããå®è£
ããæ¹æ³ãšããŠã©ã ãåŒãç»å ŽããŸããã
å Žåã«ãã£ãŠã¯ãå¿åã¯ã©ã¹ã®ä»£æ¿ãšããŠã ãã€ãã³ãŒãã¬ãã«ã§ã¯ãã©ã ãåŒã¯invokedynamic
眮ãæããããŸãã ãã®åœä»€ã¯ãæ©èœçã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£
ãäœæããããã«äœ¿çšããããã®å¯äžã®ã¡ãœããã¯ãã©ã ãåŒã®æ¬äœã§å®çŸ©ãããã³ãŒããå«ãå®éã®ã¡ãœãããžã®åŒã³åºããå§ä»»ããŸãã
ããšãã°ã次ã®ã³ãŒãããããŸãã
void printElements(List<String> strings){ strings.forEach(item -> System.out.println("Item = %s", item)); }
ãã®ã³ãŒãã¯ãJavaã³ã³ãã€ã©ã«ãã£ãŠæ¬¡ã®ãããªãã®ã«å€æãããŸãã
private static void lambda_forEach(String item) {
invokedynamic
åœä»€ã¯ããã®ãããªJavaã³ãŒããšããŠå€§ãŸãã«è¡šãããšãã§ããŸãã
private static CallSite cs; void printElements(List<String> strings) { Consumer<String> lambda;
ã芧ã®ãšããã LambdaMetafactory
ã䜿çšããŠãã¿ãŒã²ããã¡ãœããã®ãã³ãã©ãŒãè¿ããã¡ã¯ããªã¡ãœãããæäŸããCallSiteãäœæããŸãã ãã®ã¡ãœããã¯ã invokeExact
ã䜿çšããŠæ©èœã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£
ãè¿ããŸãã ã©ã ãåŒã«ãã£ããã£ããã倿°ãããå Žåã invokeExact
ã¯ãããã®å€æ°ãå®éã®ãã©ã¡ãŒã¿ãŒãšããŠåãå
¥ããŸãã
Oracle JRE 8ã§ã¯ãã¡ã¿ãã¡ã¯ããªãŒã¯ObjectWeb Asmã䜿çšããŠJavaã¯ã©ã¹ãåçã«çæããŸããããã«ãããæ©èœçãªã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããã¯ã©ã¹ãäœæãããŸãã ã©ã ãåŒãå€éšå€æ°ããã£ããã£ããå Žåãäœæãããã¯ã©ã¹ã«è¿œå ã®ãã£ãŒã«ãã远å ã§ããŸãã ããã¯Javaã®å¿åã¯ã©ã¹ã«äŒŒãŠããŸãããæ¬¡ã®éãããããŸãã
- å¿åã¯ã©ã¹ã¯ãJavaã³ã³ãã€ã©ãŒã«ãã£ãŠçæãããŸãã
- ã©ã ãåŒãå®è£
ããããã®ã¯ã©ã¹ã¯ãå®è¡æã«JVMã«ãã£ãŠäœæãããŸãã
ã¡ã¿ãã¡ã¯ããªãŒã®å®è£
ã¯ãJVMãã³ããŒãšããŒãžã§ã³ã«äŸåããŸã
ãã¡ããã invokedynamic
ã¯Javaã®ã©ã ãåŒã ãã«äœ¿çšãããããã§ã¯ãããŸããã äž»ã«ãJVMç°å¢ã§åçèšèªãå®è¡ãããšãã«äœ¿çšãããŸãã Javaã«çµã¿èŸŒãŸããŠããNashorn JavaScript ãšã³ãžã³ã¯ ããã®åœä»€ãå€çšããŠããŸãã
次ã«ã LambdaMetafactory
ã¯ã©ã¹ãšãã®æ©èœã«æ³šç®ããŸãã æ¬¡ãž
ãã®èšäºã®ã»ã¯ã·ã§ã³ã§ã¯ãã¡ã¿ãã¡ã¯ããªãŒã¡ãœããã®ä»çµã¿ãšMethodHandleãšã¯äœããååã«çè§£ããŠããããšãåæãšããŠããŸã
ã©ã ãåŒã®ããªãã¯
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãæ¥åžžã®ã¿ã¹ã¯ã§äœ¿çšããåçãªã©ã ããæ§ç¯ããæ¹æ³ã瀺ããŸãã
ãã§ãã¯æžã¿ã®äŸå€ãšã©ã ã
Javaã«ååšãããã¹ãŠã®æ©èœã€ã³ã¿ãŒãã§ãŒã¹ããã§ãã¯äŸå€ããµããŒãããªãããšã¯ç§å¯ã§ã¯ãããŸããã éåžžã®äŸå€ããããã§ãã¯ãããäŸå€ã®å©ç¹ã¯ãéåžžã«é·å¹Žã«ãããïŒãããŠãŸã ç±ãïŒè°è«ã§ãã
ããããJava Streamsãšçµã¿åãããŠã©ã ãåŒå
ã®ãã§ãã¯æžã¿äŸå€ãå«ãã³ãŒãã䜿çšããå¿
èŠãããå Žåã¯ã©ãã§ããããã ããšãã°ãæååã®ãªã¹ããæ¬¡ã®ãããªURLã®ãªã¹ãã«å€æããå¿
èŠããããŸãã
Arrays.asList("http://localhost/", "https://github.com").stream() .map(URL::new) .collect(Collectors.toList())
ã¹ããŒå¯èœãªäŸå€ã¯URLïŒStringïŒã®ã³ã³ã¹ãã©ã¯ã¿ãŒã§å®£èšãããŠããããã Functiionã¯ã©ã¹ã®ã¡ãœããåç
§ãšããŠçŽæ¥äœ¿çšããããšã¯ã§ããŸããã
ããããããããããã®ããªãã¯ãããã§äœ¿çšããå Žåããšèšãã§ãããã
public static <T> T uncheckCall(Callable<T> callable) { try { return callable.call(); } catch (Exception e) { return sneakyThrow(e); } } private static <E extends Throwable, T> T sneakyThrow0(Throwable t) throws E { throw (E)t; } public static <T> T sneakyThrow(Throwable e) { return Util.<RuntimeException, T>sneakyThrow0(e); }
ããã¯æ±ãããã¯ã§ãã çç±ã¯æ¬¡ã®ãšããã§ãã
- try-catchãããã¯ã䜿çšãããŸãã
- åã³äŸå€ãã¹ããŒãããŸãã
- Javaã§ã®åæ¶å»ã®äžæ£äœ¿çšã
ãã®åé¡ã¯ã次ã®äºå®ã«é¢ããç¥èã䜿çšããŠããããåæ³çãªãæ¹æ³ã§è§£æ±ºã§ããŸãã
- ãã§ãã¯ãããäŸå€ã¯ãJavaã³ã³ãã€ã©ã¬ãã«ã§ã®ã¿èªèãããŸãã
throws
ã»ã¯ã·ã§ã³ã¯ãJVMã¬ãã«ã§ã»ãã³ãã£ãã¯å€ãæããªãã¡ãœããã®åãªãã¡ã¿ããŒã¿ã§ãã- ãã§ãã¯ãããäŸå€ãšéåžžã®äŸå€ã¯ãJVMã®ãã€ãã³ãŒãã¬ãã«ã§ã¯åºå¥ã§ããŸããã
解決çã¯ã throws
ã»ã¯ã·ã§ã³ã®ãªãã¡ãœããã§Callable.call
ã¡ãœãããã©ããããããšã§ãã
static <V> V callUnchecked(Callable<V> callable){ return callable.call(); }
Callable.call
ã¯throws
ã»ã¯ã·ã§ã³ã§ãã§ãã¯äŸå€ã宣èšããããããã®ã³ãŒãã¯ã³ã³ãã€ã«ãããŸããã ãã ããåçã«æ§ç¯ãããã©ã ãåŒã䜿çšããŠãã®ã»ã¯ã·ã§ã³ãåé€ã§ããŸãã
æåã«ã throws
ã»ã¯ã·ã§ã³ãæããªãæ©èœã€ã³ã¿ãŒãã§ã€ã¹ã宣èšããå¿
èŠããããŸãã
ãã ãã Callable.call
åŒã³åºããå§ä»»ã§ããã®ã¯èª°Callable.call
ïŒ
@FunctionalInterface interface SilentInvoker { MethodType SIGNATURE = MethodType.methodType(Object.class, Callable.class);
2çªç®ã®ã¹ãããã¯ã LambdaMetafactory
ã䜿çšããŠãã®ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£
ãäœæãã SilentInvoker.invoke
ã¡ãœããã®Callable.call
ã¡ãœããã«å§ä»»ããããšã§ãã åè¿°ã®ããã«ã throws
ã»ã¯ã·ã§ã³ã¯ãã€ãã³ãŒãã¬ãã«ã§ã¯ç¡èŠãããããã SilentInvoker.invoke
ã¡ãœããã¯ãäŸå€ã宣èšããã«Callable.call
ã¡ãœãããåŒã³åºãããšãã§ããŸãã
private static final SilentInvoker SILENT_INVOKER; final MethodHandles.Lookup lookup = MethodHandles.lookup(); final CallSite site = LambdaMetafactory.metafactory(lookup, "invoke", MethodType.methodType(SilentInvoker.class), SilentInvoker.SIGNATURE, lookup.findVirtual(Callable.class, "call", MethodType.methodType(Object.class)), SilentInvoker.SIGNATURE); SILENT_INVOKER = (SilentInvoker) site.getTarget().invokeExact();
3çªç®ã«ãäŸå€ã宣èšããã«Callable.call
ãåŒã³åºããã«ããŒã¡ãœãããèšè¿°ããŸãã
public static <V> V callUnchecked(final Callable<V> callable) { return SILENT_INVOKER.invoke(callable); }
ããã§ããã§ãã¯æžã¿äŸå€ã®åé¡ãªãã¹ããªãŒã ãæžãæããããšãã§ããŸãã
Arrays.asList("http://localhost/", "https://dzone.com").stream() .map(url -> callUnchecked(() -> new URL(url))) .collect(Collectors.toList());
callUnchecked
ã¯ãã§ãã¯æžã¿äŸå€ã宣èšããªãããããã®ã³ãŒãã¯åé¡ãªãã³ã³ãã€ã«ãããŸãã ããã«ããã®ã¡ãœããã®åŒã³åºãã¯ã SilentOnvoker
ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããJVMå
šäœã®1ã€ã®ã¯ã©ã¹ã§ããããã SilentOnvoker
ã€ã³ã©ã€ã³ãã£ãã·ã¥ã䜿çšããŠã€ã³ã©ã€ã³åã§ããŸãã
Callable.call
ã®å®è£
ãå®è¡æã«äŸå€ãã¹ããŒããå Žåãåé¡ãªãåŒã³åºãåŽé¢æ°ã«ãã£ãŠCallable.call
ãããŸãã
try{ callUnchecked(() -> new URL("Invalid URL")); } catch (final Exception e){ System.out.println(e); }
ãã®æ¹æ³ã®å¯èœæ§ã«ãããããããæ¬¡ã®æšå¥šäºé
ãåžžã«èŠããŠããå¿
èŠããããŸãã
åŒã³åºãããã³ãŒããäŸå€ãã¹ããŒããªãããšã確å®ãªå Žåã«ã®ã¿ãcallUncheckedã§ãã§ãã¯äŸå€ãé衚瀺ã«ããŸã
次ã®äŸã¯ããã®ã¢ãããŒãã®äŸã瀺ããŠããŸãã
callUnchecked(() -> new URL("https://dzone.com"));
ãã®ã¡ãœããã®å®å
šãªå®è£
ã¯ããã«ãããŸã ãããã¯SNAMPãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã®äžéšã§ãã
ã²ãã¿ãŒãšã»ãã¿ãŒã®äœ¿çš
ãã®ã»ã¯ã·ã§ã³ã¯ãJSONãThriftãªã©ã®ããŸããŸãªããŒã¿åœ¢åŒã®ã·ãªã¢ã©ã€ãŒãŒã·ã§ã³/ãã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ãäœæãã人ã«åœ¹ç«ã¡ãŸãã ããã«ãJavaBeansã®Getterããã³Setterã®ãªãã¬ã¯ã·ã§ã³ã«ã³ãŒãã倧ããäŸåããŠããå Žåãéåžžã«äŸ¿å©ã§ãã
JavaBeanã§å®£èšãããã²ãã¿ãŒã¯ããã©ã¡ãŒã¿ãŒãæããã void
以å€ã®æ»ãããŒã¿åãæã€getXXX
ãšããã¡ãœããã§ãã JavaBeanã§å®£èšãããã»ãã¿ãŒã¯ã1ã€ã®ãã©ã¡ãŒã¿ãŒãæã¡ã void
ãè¿ãsetXXX
ãšããååã®ã¡ãœããã§ãã ãããã®2ã€ã®è¡šèšã¯ãæ©èœçãªã€ã³ã¿ãŒãã§ã€ã¹ãšããŠè¡šãããšãã§ããŸãã
- Getterã¯Functionã¯ã©ã¹ã§è¡šãããšãã§ããåŒæ°ã¯
this
ã®å€ã§ãã - ã»ãã¿ãŒã¯BiConsumerã¯ã©ã¹ã§è¡šãããšãã§ããŸããæåã®åŒæ°ã¯
this
ã§ã2çªç®ã®åŒæ°ã¯Setterã«æž¡ãããå€ã§ãã
ããã§ãã²ãã¿ãŒãŸãã¯ã»ãã¿ãŒããããã«å€æã§ãã2ã€ã®ã¡ãœãããäœæããŸã
æ©èœçã€ã³ã¿ãŒãã§ãŒã¹ã ãããŠãäž¡æ¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ããžã§ããªãã¯ã§ããããšã¯é¢ä¿ãããŸããã ã¿ã€ããæ¶å»ããåŸ
å®éã®ããŒã¿åã¯Object
ãŸãã æ»ãå€ã®åãšåŒæ°ã®èªåãã£ã¹ãã¯ã LambdaMetafactory
ã䜿çšããŠLambdaMetafactory
ã§ããŸãã ããã«ã Guavaã©ã€ãã©ãªã¯ãåãã²ãã¿ãŒãšã»ãã¿ãŒã®ã©ã ãåŒããã£ãã·ã¥ããã®ã«åœ¹ç«ã¡ãŸãã
æåã®ã¹ãããïŒã²ãã¿ãŒãšã»ãã¿ãŒã®ãã£ãã·ã¥ãäœæããŸãã Reflection APIã®Methodã¯ã©ã¹ã¯ãå®éã®ã²ãã¿ãŒãŸãã¯ã»ãã¿ãŒã衚ããããŒãšããŠäœ¿çšãããŸãã
ãã£ãã·ã¥å€ã¯ãç¹å®ã®ã²ãã¿ãŒãŸãã¯ã»ãã¿ãŒçšã®åçã«æ§ç¯ãããæ©èœã€ã³ã¿ãŒãã§ã€ã¹ã§ãã
private static final Cache<Method, Function> GETTERS = CacheBuilder.newBuilder().weakValues().build(); private static final Cache<Method, BiConsumer> SETTERS = CacheBuilder.newBuilder().weakValues().build();
次ã«ãã²ãã¿ãŒãŸãã¯ã»ãã¿ãŒãžã®åç
§ã«åºã¥ããŠæ©èœã€ã³ã¿ãŒãã§ã€ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæãããã¡ã¯ããªã¡ãœãããäœæããŸãã
private static Function createGetter(final MethodHandles.Lookup lookup, final MethodHandle getter) throws Exception{ final CallSite site = LambdaMetafactory.metafactory(lookup, "apply", MethodType.methodType(Function.class), MethodType.methodType(Object.class, Object.class),
颿°åã€ã³ã¿ãŒãã§ã€ã¹ã®Object
åã®åŒæ°ïŒåæ¶å»åŸïŒãšåŒæ°ã®å®éã®åãšæ»ãå€ãšã®éã®èªåå倿ã¯ã samMethodType
ãšinstantiatedMethodType
éãïŒã¡ã¿ãã¡ã¯ããªã¡ãœããã®3çªç®ãš5çªç®ã®åŒæ°ïŒã䜿çšããŠå®çŸãããŸãã ã€ã³ã¹ã¿ã³ã¹åãããã¡ãœããã®ã¿ã€ãã¯ãã©ã ãåŒã®å®è£
ãæäŸããã¡ãœããã®ç¹æ®åã§ãã
第äžã«ããã£ãã·ã³ã°ããµããŒããããããã®å·¥å Žã®ãã¡ãµãŒããäœæããŸãã
public static Function reflectGetter(final MethodHandles.Lookup lookup, final Method getter) throws ReflectiveOperationException { try { return GETTERS.get(getter, () -> createGetter(lookup, lookup.unreflect(getter))); } catch (final ExecutionException e) { throw new ReflectiveOperationException(e.getCause()); } } public static BiConsumer reflectSetter(final MethodHandles.Lookup lookup, final Method setter) throws ReflectiveOperationException { try { return SETTERS.get(setter, () -> createSetter(lookup, lookup.unreflect(setter))); } catch (final ExecutionException e) { throw new ReflectiveOperationException(e.getCause()); } }
Java Reflection APIã䜿çšããŠMethod
ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ããååŸããã¡ãœããæ
å ±ã¯ã MethodHandle
ç°¡åã«å€æã§ããŸãã ã¯ã©ã¹ã€ã³ã¹ã¿ã³ã¹ã¡ãœããã«ã¯ããã®ã¡ãœããã«ãããæž¡ãthis
ã«äœ¿çšãããé ãããæåã®åŒæ°ãåžžã«ããããšã«æ³šæããŠãã ããã éçã¡ãœããã«ã¯ããã®ãããªãã©ã¡ãŒã¿ãŒã¯ãããŸããã ããšãã°ã Integer.intValue()
ã¡ãœããã®å®éã®çœ²åã¯int intValue(Integer this)
ããã«èŠããŸãã ãã®ããªãã¯ã¯ãã²ãã¿ãŒãšã»ãã¿ãŒã®æ©èœã©ãããŒã®å®è£
ã§äœ¿çšãããŸãã
次ã«ãã³ãŒãããã¹ãããŸãã
final Date d = new Date(); final BiConsumer<Date, Long> timeSetter = reflectSetter(MethodHandles.lookup(), Date.class.getDeclaredMethod("setTime", long.class)); timeSetter.accept(d, 42L);
ãã£ãã·ã¥ãããã²ãã¿ãŒããã³ã»ãã¿ãŒã䜿çšãããã®ã¢ãããŒãã¯ãã·ãªã¢ã©ã€ãºããã³ãã·ãªã¢ã©ã€ãºäžã«ã²ãã¿ãŒããã³ã»ãã¿ãŒã䜿çšããã·ãªã¢ã©ã€ãŒãŒã·ã§ã³/ãã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ã©ã€ãã©ãªïŒãžã£ã¯ãœã³ãªã©ïŒã§å¹æçã«äœ¿çšã§ããŸãã
LambdaMetaFactory
ã䜿çšããŠåçã«çæãããå®è£
ã§æ©èœã€ã³ã¿ãŒãã§ãŒã¹ãåŒã³åºãããšã¯ãJava Reflection APIãä»ããŠåŒã³åºããããã¯ããã«é«éã§ãã
ã³ãŒãã®å®å
šçã¯ããã«ããã SNAMPã©ã€ãã©ãªã®äžéšã§ãã
å¶éãšãã°
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãJavaã³ã³ãã€ã©ãšJVMã®ã©ã ãåŒã«é¢é£ããããã€ãã®ãã°ãšå¶éã«ã€ããŠèª¬æããŸãã ãããã®å¶éã¯ãã¹ãŠãWindowsããã³Linuxçšã®javac
ããŒãžã§ã³1.8.0_131ã䜿çšããOpenJDKããã³Oracle JDKã§åçŸã§ããŸãã
ã¡ãœãããã³ãã©ãŒããã©ã ãåŒãäœæãã
ãåç¥ã®ããã«ãã©ã ãåŒã¯LambdaMetaFactory
ã䜿çšããŠåçã«æ§ç¯ã§ããŸãã ãããè¡ãã«ã¯ããã³ãã©ãŒïŒ MethodHandle
ã¯ã©ã¹ïŒãå®çŸ©ããå¿
èŠããããŸããããã¯ãæ©èœã€ã³ã¿ãŒãã§ãŒã¹ã§å®çŸ©ãããŠããå¯äžã®ã¡ãœããã®å®è£
ã瀺ããŸãã ãã®ç°¡åãªäŸãèŠãŠã¿ãŸãããã
final class TestClass { String value = ""; public String getValue() { return value; } public void setValue(final String value) { this.value = value; } } final TestClass obj = new TestClass(); obj.setValue("Hello, world!"); final MethodHandles.Lookup lookup = MethodHandles.lookup(); final CallSite site = LambdaMetafactory.metafactory(lookup, "get", MethodType.methodType(Supplier.class, TestClass.class), MethodType.methodType(Object.class), lookup.findVirtual(TestClass.class, "getValue", MethodType.methodType(String.class)), MethodType.methodType(String.class)); final Supplier<String> getter = (Supplier<String>) site.getTarget().invokeExact(obj); System.out.println(getter.get());
ãã®ã³ãŒãã¯æ¬¡ãšåçã§ãïŒ
final TestClass obj = new TestClass(); obj.setValue("Hello, world!"); final Supplier<String> elementGetter = () -> obj.getValue(); System.out.println(elementGetter.get());
ãããã getValue
ãæãã¡ãœãããã³ãã©ãŒãã²ãã¿ãŒãã£ãŒã«ãã衚ããã³ãã©ãŒã§çœ®ãæãããšã©ããªãã§ããããã
final CallSite site = LambdaMetafactory.metafactory(lookup, "get", MethodType.methodType(Supplier.class, TestClass.class), MethodType.methodType(Object.class), lookup.findGetter(TestClass.class, "value", String.class),
findGetter
ãã²ãã¿ãŒãã£ãŒã«ãããã€ã³ãããæ£ãã眲åãæã€ãã³ãã©ãŒãè¿ãããããã®ã³ãŒãã¯äºæ³ã©ããã«æ©èœããã¯ãã§ãã ãã ãããã®ã³ãŒããå®è¡ãããšã次ã®äŸå€ã衚瀺ãããŸãã
java.lang.invoke.LambdaConversionException: Unsupported MethodHandle kind: getField
è峿·±ãããšã«ã MethodHandleProxiesã䜿çšãããšããã£ãŒã«ãã®ã²ãã¿ãŒã¯åé¡ãªãæ©èœããŸãã
final Supplier<String> getter = MethodHandleProxies .asInterfaceInstance(Supplier.class, lookup.findGetter(TestClass.class, "value", String.class) .bindTo(obj));
MethodHandleProxies
ã¯ãã©ã ãåŒãåçã«äœæããè¯ãæ¹æ³ã§ã¯ãªãããšã«æ³šæããŠãã ããããã®ã¯ã©ã¹ã¯ãåã«MethodHandle
ããããã·ã¯ã©ã¹ã§ã©ããããinvocationHandler.invokeãMethodHandle.invokeWithArgumentsã«å§ä»»ããããã§ã ã ãã®ã¢ãããŒãã¯Java Reflectionã䜿çšããéåžžã«æéãããããŸãã
åã«ç€ºããããã«ããã¹ãŠã®ã¡ãœãããã³ãã©ãŒã䜿çšããŠå®è¡æã«ã©ã ãåŒãäœæã§ããããã§ã¯ãããŸããã
ã©ã ãåŒãåçã«äœæããããã«äœ¿çšã§ããã¡ãœãããã³ãã©ã¯æ°çš®é¡ã®ã¿ã§ãã
ããã«ãããŸãïŒ
- REF_invokeInterfaceïŒã€ã³ã¿ãŒãã§ã€ã¹ã¡ãœããã®Lookup.findVirtualã䜿çšããŠäœæã§ããŸã
- REF_invokeVirtualïŒã¯ã©ã¹ä»®æ³ã¡ãœããã®Lookup.findVirtualã䜿çšããŠäœæã§ããŸã
- REF_invokeStaticïŒéçã¡ãœããã®Lookup.findStaticã䜿çšããŠäœæ
- REF_newInvokeSpecialïŒã³ã³ã¹ãã©ã¯ã¿ãŒã®Lookup.findConstructorã䜿çšããŠäœæã§ããŸã
- REF_invokeSpecialïŒLookup.findSpecialã䜿çšããŠäœæã§ããŸã
ãã©ã€ããŒãã¡ãœããããã³ã¯ã©ã¹ä»®æ³ã¡ãœããã䜿çšããäºåãã€ã³ãã£ã³ã°
ä»ã®ã¿ã€ãã®ãã³ãã©ãŒã¯LambdaConversionException
ãšã©ãŒãLambdaConversionException
ãŸãã
äžè¬çãªäŸå€
ãã®ãã°ã¯ãJavaã³ã³ãã€ã©ãšã throws
ã»ã¯ã·ã§ã³ã§äžè¬çãªäŸå€ã宣èšããæ©èœã«é¢é£ããŠããŸãã æ¬¡ã®ã³ãŒãäŸã¯ããã®åäœã瀺ããŠããŸãã
interface ExtendedCallable<V, E extends Exception> extends Callable<V>{ @Override V call() throws E; } final ExtendedCallable<URL, MalformedURLException> urlFactory = () -> new URL("http://localhost"); urlFactory.call();
URL
ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ãŒãMalformedURLException
ã¹ããŒããããããã®ã³ãŒããã³ã³ãã€ã«ããå¿
èŠããããŸãã ããããã³ã³ãã€ã«ã¯ããŸããã æ¬¡ã®ãšã©ãŒã¡ãã»ãŒãžã衚瀺ãããŸãã
Error:(46, 73) java: call() in <anonymous Test$CODEgt; cannot implement call() in ExtendedCallable overridden method does not throw java.lang.Exception
ãã ããã©ã ãåŒãå¿åã¯ã©ã¹ã«çœ®ãæãããšãã³ãŒãã¯ã³ã³ãã€ã«ãããŸãã
final ExtendedCallable<URL, MalformedURLException> urlFactory = new ExtendedCallable<URL, MalformedURLException>() { @Override public URL call() throws MalformedURLException { return new URL("http://localhost"); } }; urlFactory.call();
ããã¯æ¬¡ã®ãšããã§ãã
äžè¬çãªäŸå€ã®åæšè«ã¯ãã©ã ãåŒãšçµã¿åãããŠæ£ããæ©èœããŸãã
ãã©ã¡ãŒã¿åã¿ã€ãã®å¶é
&
ïŒ <T extends A & B & C & ... Z>
èšå·ã䜿çšããŠãããã€ãã®åå¶éãæã€æ±çšãªããžã§ã¯ããæ§ç¯ã§ããŸãã
ãžã§ããªãã¯ãã©ã¡ãŒã¿ãŒã決å®ãããã®æ¹æ³ã¯ãã£ãã«äœ¿çšãããŸããããããã€ãã®å¶éããããããç¹å®ã®æ¹æ³ã§Javaã®ã©ã ãåŒã«åœ±é¿ããŸãã
- æåã®ã¿ã€ããé€ãåã¿ã€ãã®å¶çŽã¯ãã€ã³ã¿ãŒãã§ãŒã¹ã§ãªããã°ãªããŸããã
- ãã®ãããªãžã§ããªãã¯ãæã€ã¯ã©ã¹ã®çŽç²ãªããŒãžã§ã³ã§ã¯ããªã¹ãã®æåã®ã¿ã€ãã®å¶çŽã®ã¿ãèæ
®ãããŸãã
2çªç®ã®å¶éã«ãããã³ã³ãã€ã«æãšå®è¡æã«ã©ã ãåŒãžã®ãªã³ã¯ãããå Žåãã³ãŒãã®åäœãç°ãªããŸãã ãã®éãã¯ã次ã®ã³ãŒãã䜿çšããŠå®èšŒã§ããŸãã
final class MutableInteger extends Number implements IntSupplier, IntConsumer {
ãã®ã³ãŒãã¯å®å
šã«æ£ãããæ£åžžã«ã³ã³ãã€ã«ãããŸãã MutableInteger
ã¯ã©ã¹ã¯ããžã§ããªãã¯åTã®å¶éãæºãããŸãã
MutableInteger
ã¯Number
ç¶æ¿ããŸããMutableInteger
å®è£
ãIntSupplier
ã
ãã ããå®è¡æã«äŸå€ãçºçããŠã³ãŒããã¯ã©ãã·ã¥ããŸãã
java.lang.BootstrapMethodError: call site initialization exception at java.lang.invoke.CallSite.makeSite(CallSite.java:341) at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307) at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297) at Test.minValue(Test.java:77) Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Number; not a subtype of implementation type interface java.util.function.IntSupplier at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233) at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303) at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
ããã¯ãJavaStreamãã€ãã©ã€ã³ãçŽç²ãªåïŒãã®å Žåã¯Number
ã¯ã©ã¹ïŒã®ã¿ããã£ããã£ãã IntSupplier
ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããªãããã«IntSupplier
ãŸãã ãã®åé¡ã¯ãã¡ãœãããžã®åç
§ãšããŠäœ¿çšãããå¥ã®ã¡ãœããã§ãã©ã¡ãŒã¿ãŒã®åãæç€ºçã«å®£èšããããšã§ä¿®æ£ã§ããŸãã
private static int getInt(final IntSupplier i){ return i.getAsInt(); } private static <T extends Number & IntSupplier> OptionalInt findMinValue(final Collection<T> values){ return values.stream().mapToInt(UtilsTest::getInt).min(); }
ãã®äŸã¯ãã³ã³ãã€ã©ãšã©ã³ã¿ã€ã ã§ã®äžæ£ãªåæšè«ã瀺ããŠããŸãã
ã³ã³ãã€ã«æããã³å®è¡æã«ã©ã ãåŒã䜿çšããããšãšçµã¿åããããæ±çšãã©ã¡ãŒã¿ã¿ã€ãã®ããã€ãã®å¶çŽã®åŠçã«ã¯äžè²«æ§ããããŸãã