创建 BiConsumer 作为不带反射的字段设置器

2023-12-02

我尝试在我的一个脚本中获得最大性能,而不进行重大重构。

我发现了使用反射从 Field 创建 BiConsumer 的方法。

return (c, v) -> {
    try {
        field.set(c, v);
    } catch (final Throwable e) {
        throw new RuntimeException("Could not set field: " + field, e);
    }
};

反射有缓慢的名声。 所以我想我可以使用方法句柄。

Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflectSetter(field);
return (c, v) -> {
    try {
        mh.invoke(c, v);
    } catch (final Throwable e) {
        throw new RuntimeException("Could not set field: " + field, e);
    }
};

这已经快了一点点。 然而BiConsumer is a FunctionalInterface它可以以某种方式生成。

public static <C, V> BiConsumer<C, V> createSetter(final MethodHandles.Lookup lookup,
        final Field field) throws Exception {
    final MethodHandle setter = lookup.unreflectSetter(field);
    final CallSite site = LambdaMetafactory.metafactory(lookup,
            "accept",
            MethodType.methodType(BiConsumer.class),
            MethodType.methodType(void.class, Object.class, Object.class), // signature of method BiConsumer.accept after type erasure
            setter,
            setter.type()); // actual signature of setter
    return (BiConsumer<C, V>) site.getTarget().invokeExact();
}

但是后来我得到了一个我不太理解的异常

Exception in thread "main" java.lang.invoke.LambdaConversionException: Unsupported MethodHandle kind: putField org.sample.dto.TestDTO.name:(String)void
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:182)
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
    at org.sample.bench.MyBenchmark.createSetter(MyBenchmark.java:120)
    at org.sample.bench.MyBenchmark.main(MyBenchmark.java:114)

我必须以何种方式正确生成该设置器才能提高性能。 (没有实际添加 setter 方法)


您可以使用调用者MethodHandle:

public static <C, V> BiConsumer<C, V> createSetter(
                     MethodHandles.Lookup lookup, Field field) throws Throwable {
    final MethodHandle setter = lookup.unreflectSetter(field);
    MethodType type = setter.type();
    if(field.getType().isPrimitive())
        type = type.wrap().changeReturnType(void.class);
    final CallSite site = LambdaMetafactory.metafactory(lookup,
        "accept", MethodType.methodType(BiConsumer.class, MethodHandle.class),
        type.erase(), MethodHandles.exactInvoker(setter.type()), type);
    return (BiConsumer<C, V>)site.getTarget().invokeExact(setter);
}

自从LambdaMetafactory不允许为字段方法句柄生成函数实例,上面的代码为方法句柄创建函数实例相当于调用invokeExact在字段访问器方法句柄上。

在最坏的情况下,生成的代码与执行手动调用方法句柄的 lambda 表达式生成的代码没有什么不同。invoke方法,因此性能将与

public static <C, V> BiConsumer<C, V> createSetterU(
                     MethodHandles.Lookup lookup, Field field) throws Throwable {
    MethodHandle setter = lookup.unreflectSetter(field);
    return (c, v) -> {
        try {
            setter.invoke(c, v);
        } catch (final Throwable e) {
            throw new RuntimeException("Could not set field: " + field, e);
        }
    };
}

但是,在某些情况下,调用程序方法句柄可能会稍微更有效。首先,它使用等价于invokeExact而不是invoke,一个选项,通用代码由于类型擦除而无法使用。其次,当代码图中不涉及用户代码时,可能会进行一些内部调整。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建 BiConsumer 作为不带反射的字段设置器 的相关文章

随机推荐

  • 间隙填充时间栅格对象

    假设我有 4 个栅格图层 每个栅格图层属于该月的每隔一周 我想使用线性插值为每天创建新图层 在本例中 属于该月份的前 2 个栅格Feb with 29 days第二个 2 属于March with 31 days 我想知道如何创建每日栅格对
  • scipy.optimize.minimize 没有给出最小值,即使它看到该值

    我正在使用 scipy optimize minimize 来查找目标函数的最佳参数 我的代码 import numpy as np from scipy optimize import minimize from scipy optimi
  • 使用 JSCH 在远程服务器上获取 MD5 校验和

    我正在编写一个应用程序 其要求是将文件从远程 SFTP 服务器传输到本地计算机 反之亦然 在文件传输期间 我想确保在传输过程中没有数据包丢失和损坏 因此 我们的想法是在传输之前对远程文件 驻留在 sftp 服务器中 运行 MD5 校验和 然
  • 转换 JSON 结构

    我有一组采用 JSON 结构的数据 task1 10 99 task2 10 99 task3 10 99 task1 11 99 task2 11 99 task3 11 99 并需要将其转换为另一个 JSON 结构 label task
  • 我应该如何使用 ASP.NET MVC 路由实现本地化?

    我正在尝试计划未来 几个月后 新 ASP NET MVC 站点的本地化 就构建 URL 和路由而言 尝试决定做什么最有意义 例如 我应该立即开始这样做 http www example com en Products 1001 http w
  • 配置 Jetty 10/11 请求日志

    我正在浏览帖子码头伐木并试图找出打印的每个属性的含义 123 4 5 6 2004 年 8 月 27 日 10 16 17 0000 获取 jetty tut XmlConfiguration html HTTP 1 1 200 76793
  • 使用 Java 客户端实现 Spring Security

    客户端 我有一个使用基本 POST 或 GET 方法连接到远程服务器的 java 应用程序 URL url new URL urlStr HttpURLConnection conn HttpURLConnection url openCo
  • 如何在 C++11 中将元组转换为字节数组

    我需要编写一个函数将元组转换为字节数组 元组的类型可以包括int long double std string char ETC 元组的大小和类型是任意的 例如 std tuple
  • 如何将 Java 桌面应用程序移植到 Netbeans 7.1

    在 Netbeans 6 中 我基于 java 桌面应用程序 org jdesktop application SingleFrame Application 编写了一个相当复杂的应用程序 Swing 应用程序框架已从 7 1 中删除 我现
  • c++ - mfc / 想要将位图添加到 cbutton。 CButton 没有成员 setBitmap 并且 BM_SETIMAGE 也不能用于 sendMessage

    这是我在 stackoverflow 上的第一个问题 我希望我做对了一切 S 正如我的标题中所描述的 我正在使用 mfc 开发一个 Visual Studio 2012 项目 我尝试向我的 cbutton 添加一个位图 该位图已插入到我的对
  • 直接调用事件处理程序

    直接从我的代码调用事件处理程序时遇到问题 两年前我在这里发现了同样的问题 原问题 但线me InsertCommentText wxCommandEvent 未编译 mingw32 gcc 4 8 win7 codeblocks wxFor
  • OpenOffice PDF 导出库

    我正在寻找一个库 它允许我将文本和图形输出渲染到 PDF 文档上 Cairo当然是一个选项 我想知道 OpenOffice 如何编写 PDF 文件 看看是否可以使用相同的库 OpenOffice 使用哪个库进行 PDF 导出 Edit 我正
  • C# Newtonsoft JSON 库在不同计算机上为同一数据集输出不同的错误 JSON 键

    我不知道如何解决这个问题 我能想到的解决这个问题的方法是 我的开发机器工作完美是 32 位 其他测试的计算机是 64 位 顺便说一句 我周围没有其他 32 位机器可以测试 无论如何 这是一个奇怪的场景 现在来说说这个问题 我在用Newton
  • 如何使用python获取默认浏览器的名称

    我的脚本每 X 秒运行一个命令 如果命令类似于 start www gt 在默认浏览器中打开网站 我希望能够在下次执行该命令之前关闭浏览器 下面是脚本的一小部分 if start www in command time sleep inte
  • 将数组列表传递给 WCF 应用程序

    I am new to WCF I have a scenario where i have 当我尝试传递数组列表时 它给出了错误 请看一下图像 ICommission服务定义 GeneratedCode System ServiceMod
  • 可以创建一个工厂来实例化自定义表单验证器吗?

    使用 Zend 框架 2 2 4 我的验证器工厂在验证时似乎并不 存在 如果我尝试从容纳表单的控制器实例化验证器 它反而可以正常工作 这有效 mycustomvalidator this gt getServiceLocator gt ge
  • C# 透明 GUI

    大家好 我想知道如何在 C 中制作一个 透明 的 GUI 现在我不是在谈论透明度键等 我想制作一个使用 vistas aero 主题的窗口 但不是表单中的控件 我只是希望它显示更多 seethru aero 外观 我还想从窗口中删除所有按钮
  • 如何使用 Mule ESB、Mule Studio 读取返回 JSON 对象的 REST 服务并将其存储到 PostgreSQL 中

    所以我有一个基于 REST 的服务 托管在 http localhost 35798 RestServiceImpl svc json 567 如果我查询 我得到的结果为 JSONDataResult You requested produ
  • 如何使用PHP获取客户端的MAC地址?

    如何使用 PHP 或 javascript 获取 MAC 地址 MAC 地址 低级本地网络接口地址 无法通过 IP 路由器 您无法从远程服务器找到客户端 MAC 地址 在本地子网中 MAC 地址通过 ARP 系统映射到 IP 地址 本地网络
  • 创建 BiConsumer 作为不带反射的字段设置器

    我尝试在我的一个脚本中获得最大性能 而不进行重大重构 我发现了使用反射从 Field 创建 BiConsumer 的方法 return c v gt try field set c v catch final Throwable e thr