使用java 8 lambda表达式打印有关错误的调试信息

aal*_*lku 9 java reflection debugging lambda java-8

我想使用静态方法作为setter helper来捕获异常并打印有关失败操作的调试信息.我不希望只有例外细节.我想显示正在设置的属性,以便详细帮助快速调试问题.我正在使用Java 8.

我应该如何提供或检测所设置的财产?

我希望删除示例中的"名称"字符串并获得相同的结果.

我知道我不能对提供的提供的setter方法使用反射,该方法转换为lambda表达式然后转换为BiConsumer.

我得到了这个,但需要提供属性名称.

/** setter helper method **/
private static <E, V> void set(E o, BiConsumer<E, V> setter,
        Supplier<V> valueSupplier, String propertyName) {
    try {
        setter.accept(o, valueSupplier.get());
    } catch (RuntimeException e) {
        throw new RuntimeException("Failed to set the value of " + propertyName, e);
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

    Person p = new Person();
    Supplier<String> nameSupplier1 = () ->  "MyName";
    Supplier<String> nameSupplier2 = () -> { throw new RuntimeException(); };
    set(p, Person::setName, nameSupplier1, "name");
    System.out.println(p.getName()); // prints MyName
    set(p, Person::setName, nameSupplier2, "name"); // throws exception with message  Failed to set the value of name
    System.out.println(p.getName()); // Does not execute
Run Code Online (Sandbox Code Playgroud)

编辑:我知道反射对lambda不起作用.我知道AOP,我知道这也可以用纯粹的反射来制作,但我想知道是否有更好的方法来完成Java 7并不存在Java 7.这对我来说应该是.现在可以做一些事情,比如将setter方法传递给另一个.

Hol*_*ger 21

如果您希望方法引用作为唯一输入,您可以使用以下技巧将它们调试为可打印的名称:

public static void main(String[] args) {
  Person p = new Person();
  Supplier<String> nameSupplier1 = () -> "MyName";
  Supplier<String> nameSupplier2 = () -> { throw new RuntimeException(); };
  set(p, Person::setName, nameSupplier1);
  System.out.println(p.getName()); // prints MyName
  set(p, Person::setName, nameSupplier2); // throws exception with message
  System.out.println(p.getName()); // Does not execute
}

interface DebuggableBiConsumer<A, B> extends BiConsumer<A, B>, Serializable {}

private static <E, V> void set(
    E o, DebuggableBiConsumer<E, V> setter, Supplier<V> valueSupplier) {
  try {
    setter.accept(o, valueSupplier.get());
  } catch (RuntimeException e) {
    throw new RuntimeException("Failed to set the value of "+name(setter), e);
  }
}

private static String name(DebuggableBiConsumer<?, ?> setter) {
  for (Class<?> cl = setter.getClass(); cl != null; cl = cl.getSuperclass()) {
    try {
      Method m = cl.getDeclaredMethod("writeReplace");
      m.setAccessible(true);
      Object replacement = m.invoke(setter);
      if(!(replacement instanceof SerializedLambda))
        break;// custom interface implementation
      SerializedLambda l = (SerializedLambda) replacement;
      return l.getImplClass() + "::" + l.getImplMethodName();
    }
    catch (NoSuchMethodException e) {}
    catch (IllegalAccessException | InvocationTargetException e) {
      break;
    }
  }
  return "unknown property";
}
Run Code Online (Sandbox Code Playgroud)

限制是它将为lambda表达式(对包含lambda代码的合成方法的引用)和"unknown property"接口的自定义实现打印不是非常有用的方法引用.

  • [`MethodHandle`](http://download.java.net/jdk8/docs/api/java/lang/invoke/MethodHandle.html)非常接近.在字节代码级别上,它们可以像常量(如`Class`或`String`文字)一样使用.使用Java 8,您可以[解码直接句柄](http://download.java.net/jdk8/docs/api/java/lang/invoke/MethodHandles.Lookup.html#revealDirect-java.lang.invoke.MethodHandle - ).顺便说一下,lambda表达式/方法引用实现在内部使用它. (3认同)
  • 那么`SerializedLambda`是保持不同实现之间兼容性的*形式.理论上只有`writeReplace`方法可以用不同的机制替换.如果你想要完全安全,你必须将对象写成真实的,例如写入字节数组并解析输出.输出*必须*包含一个`SerializedLambda`用于符合实现.是的,它仅在例外情况下很慢. (2认同)
  • 我向日食小组提交了一份报告; 让我们看看修复需要多长时间.对于lambda表达式(`(...) - > ...`)的`Serialization`已经有效,它可能会变得很简单. (2认同)