草庐IT

java - 重复实例化匿名类是否浪费?

coder 2024-03-03 原文

我对一段代码的评论是这样的:

Iterable<String> upperCaseNames = Iterables.transform(
    lowerCaseNames, new Function<String, String>() {
        public String apply(String input) {
            return input.toUpperCase();
        }
    });

那个人说每次我浏览这段代码时,我都会实例化这个匿名函数类,我宁愿在静态变量中有一个实例:

static Function<String, String> toUpperCaseFn =
    new Function<String, String>() {
        public String apply(String input) {
            return input.toUpperCase();
        }
    };
...
Iterable<String> upperCaseNames =
    Iterables.transform(lowerCaseNames, toUpperCaseFn);

从表面上看,这在某种程度上是有道理的;多次实例化一个类肯定会浪费内存什么的,对吧?

另一方面,人们在代码中间实例化匿名类就像没有明天一样,编译器优化它是微不足道的。

这是一个合理的担忧吗?

最佳答案

关于 Hot Spot JVM 优化的有趣事实,如果您实例化一个未在当前方法之外传递的对象,JVM 将在字节码级别执行优化。

通常,堆栈分配与公开内存模型的语言相关联,例如 C++。您不必在 C++ 中delete 堆栈变量,因为它们会在作用域退出时自动释放。这与堆分配相反,堆分配要求您在使用完指针后将其删除。

在 Hot Spot JVM 中,分析字节码以确定对象是否可以“逃离”线程。有three levels of escape :

  1. 无转义 - 该对象仅在其创建的方法/范围内使用,不能在线程外访问该对象。
  2. Local/Arg escape - 对象由创建它的方法返回或传递给它调用的方法,但这些方法都不会将该对象放在可以在线程外访问的地方。
  3. 全局转义 - 对象被放置在可以在另一个线程中访问的地方。

这基本上类似于以下问题:1) 我是否将它传递给另一个方法或返回它,以及 2) 我是否将它与附加到 GC 根的某些东西相关联,例如 ClassLoader 或其他东西存储在 static 字段中?

在您的特定情况下,匿名对象将被标记为“本地转义”,这仅意味着对象上的任何锁(读取:同步 的使用)将被优化掉。 (为什么要在另一个线程中永远不会使用的东西上进行同步?)这与“无逃逸”不同,后者在堆栈上进行分配。请务必注意,此“分配”与堆分配不同。它真正做的是在堆栈上为非转义对象内的所有变量分配空间。如果在 no-escape 对象中有 3 个字段,intStringMyObject,那么将分配三个堆栈变量:一个 int,一个 String 引用,和一个 MyObject referenceMyObject 实例本身将仍然存储在堆中,除非它也被分析为“无法逃脱”。然后优化对象分配,构造函数/方法将使用本地堆栈变量而不是堆变量运行。

话虽这么说,但对我来说这听起来像是过早的优化。除非代码后来被证明速度很慢并且导致性能问题,否则您不应该做任何事情来降低它的可读性。对我来说,这段代码可读性很强,我不会管它。当然,这完全是主观的,但是“性能”不是更改代码的好理由,除非它与实际运行时间有关。通常,过早的优化会导致代码更难维护,性能优势微乎其微。

Java 8+ 和 Lambdas

如果分配匿名实例仍然困扰您,我建议您改用 Lambdas 来处理单一抽象方法 (SAM) 类型。 Lambda 评估是使用 invokedynamic 执行的,并且实现最终在第一次调用时仅创建 Lambda 的单个实例。可以找到更多详细信息in my answer herethis answer here .对于非 SAM 类型,您仍然需要分配一个匿名实例。在大多数用例中,这里的性能影响可以忽略不计,但在我看来,这种方式更具可读性。

引用资料

关于java - 重复实例化匿名类是否浪费?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19718353/

有关java - 重复实例化匿名类是否浪费?的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  5. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  8. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  9. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

  10. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

随机推荐