为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

大话西游666 2019-11-19 11:07:21

我想使用静态方法作为setter助手来捕获异常并打印有关失败操作的调试信息。我不只希望异常详细信息。我想显示正在设置的属性,以便详细帮助快速调试问题。我正在使用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);

    }

}

例:


    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

编辑:我知道反射对lambdas无济于事。我知道AOP,我也知道也可以通过纯反射来完成,但是我想知道是否有更好的方法可以用Java 8做到这一点,而Java 7却不存在。现在可以做类似将setter方法传递给另一个方法的事情。


查看完整描述

3 回答

?
隔江千里

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


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

}

局限性在于它不会为lambda表达式(对包含lambda代码的综合方法的引用)和"unknown property"接口的自定义实现打印出非常有用的方法引用。


查看完整回答
反对 回复 2019-11-19
?
倚天杖

那么SerializedLambda保持不同的实现之间的兼容性的形式。从writeReplace理论上讲,只有该方法可以替换为其他机制。如果您想完全安全,则必须将对象实际写入,例如写入字节数组并解析输出。输出必须包含SerializedLambda符合规范的实现。是的,它仅在例外情况下速度较慢。 

查看完整回答
反对 回复 2019-11-19
?
慕田峪9158850

MethodHandle非常接近这一点。在字节码级别,它们可以像常量(like Class或Stringliteral)一样被使用。使用Java 8可以解码直接句柄。顺便说一下,这在内部由lambda表达式/方法参考实现使用。

查看完整回答
反对 回复 2019-11-19

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信