占用内存的Enum.values()方法

我是Java 枚举的忠实拥护者 。 似乎我们一直在等待获得它,但是当我们最终获得它( J2SE 5 )时,该枚举比C和C ++提供的枚举要好得多,在我看来,这“ 值得等待” 。 与Java enum一样好,它也不是没有问题。 特别是,Java枚举的方法values()返回数组的新副本,该副本表示每次调用时可能的值。

Java语言规范阐明了枚举行为。 在Java语言规范Java SE 10 Edition中 , 第8.9节涵盖了枚举。 第8.9.3节 (“枚举成员”)列出了两个“隐式声明的方法”: public static E[] values()public static E valueOf(String name)例8.9.3-1 (“使用增强的for循环遍历枚举常量”)演示了如何调用Enum.values()遍历枚举。 但是,问题在于Enum.values()返回一个数组,而Java中的数组是可变的[Java语言规范的10.9节 (“字符数组不是字符串”)提醒我们,当在Java之间进行区分时) string和Java字符数组。]。 Java枚举是紧密不变的,因此有意义的是,每次调用该枚举以确保不更改与该枚举关联的数组时,该枚举必须返回由values()方法返回的数组的克隆。

OpenJDK 编译器-开发邮件列表上最近的一篇标题为“ 关于Enum.values()内存分配 ”的文章指出,在紧密循环中调用Enum.values()会克隆常量值数组时,会分配大量内存。 ” 该消息的发布者补充说,这“可能是出于不变性”,并指出:“我能理解。” 该消息还引用了同一邮件列表上的2012年3月消息和相关主题。

编译器开发邮件列表上的两个线程包括一些有趣的当前可用的解决方法。

  • values()返回的枚举值数组缓存为元素的private static final数组,该元素的初始private static final数组初始化为values()返回的数组。
  • 缓存枚举值的固定List
  • 创建一个枚举值的EnumSet

Brian Goetz在该线程上的消息开头是“这本质上是API设计错误; 因为values()返回一个数组,并且数组是可变的,所以每次都必须复制该数组。” [Goetz在该消息中还嘲笑了“ 冻结数组 ”(使Java数组变得不可变)的概念。]

这个问题不是新问题。 威廉·希尔兹(William Shields)在2009年12月发布的文章《 Java中的可变性,数组和临时对象的成本 》指出:“所有这些的最大问题是Java数组是可变的。” Shields在写由Enum.values()提出的特定问题之前,先解释了Java Date类中可变性的古老和众所周知的问题:

Java枚举有一个称为values()的静态方法,该方法返回该enum的所有实例的数组 Date类的课程中,这个特殊的决定令人震惊。 List本来是更明智的选择。 在内部,这意味着实例数组每次调用时都必须进行防御性复制...

对此问题的其他引用包括“ Enums.values()方法 ”(Guava线程)和“ Java的Enum.values()隐藏分配 ”(显示缓存Enum.values()返回的数组)。 上面还写了一个JDK错误: JDK-8073381 (“需要API来获取枚举值而不创建新数组”)。

下一篇代码清单中说明了本文中讨论的一些当前可用的变通方法,这是一个简单的Fruit枚举,演示了以三种不同格式缓存该枚举的值。

具有三个“值”的缓存集的Fruit.java枚举

package dustin.examples.enums;import java.util.EnumSet;
import java.util.List;/*** Fruit enum that demonstrates some currently available* approaches for caching an enum's values so that a new* copy of those values does not need to be instantiated* each time .values() is called.*/
public enum Fruit
{APPLE("Apple"),APRICOT("Apricot"),BANANA("Banana"),BLACKBERRY("Blackberry"),BLUEBERRY("Blueberry"),BOYSENBERRY("Boysenberry"),CANTALOUPE("Cantaloupe"),CHERRY("Cherry"),CRANBERRY("Cranberry"),GRAPE("Grape"),GRAPEFRUIT("Grapefruit"),GUAVA("Guava"),HONEYDEW("Honeydew"),KIWI("Kiwi"),KUMQUAT("Kumquat"),LEMON("Lemon"),LIME("Lime"),MANGO("Mango"),ORANGE("Orange"),PAPAYA("Papaya"),PEACH("Peach"),PEAR("Pear"),PLUM("Plum"),RASPBERRY("Raspberry"),STRAWBERRY("Strawberry"),TANGERINE("Tangerine"),WATERMELON("Watermelon");private String fruitName;Fruit(final String newFruitName){fruitName = newFruitName;}/** Cached fruits in immutable list. */private static final List<Fruit> cachedFruitsList = List.of(Fruit.values());/** Cached fruits in EnumSet. */private static final EnumSet<Fruit> cachedFruitsEnumSet = EnumSet.allOf(Fruit.class);/** Cached fruits in original array form. */private static final Fruit[] cachedFruits = Fruit.values();public static List<Fruit> cachedListValues(){return cachedFruitsList;}public static EnumSet<Fruit> cachedEnumSetValues(){return cachedFruitsEnumSet;}public static Fruit[] cachedArrayValues(){return cachedFruits;}
}

在许多情况下,每次调用Enum.values()必须克隆其数组的事实实际上并不重要。 也就是说,不难想象在“紧缩循环”中反复调用Enum.values()会很有用,然后每次将枚举值复制到数组中都会对内存产生明显影响的情况并不难使用以及与更大内存使用相关的问题。 如果有一种标准的方法来以更有效的内存方式访问枚举的值,那就太好了。 前面提到的两个线程讨论了一些潜在实现此功能的想法。

翻译自: https://www.javacodegeeks.com/2018/08/memory-hogging-enum-values-method.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache Spark Job的剖析

Apache Spark是通用的大规模数据处理框架。 了解spark如何执行作业对于获取大部分作业非常重要。 关于Spark评估范式的简短回顾&#xff1a;Spark使用的是惰性评估范式&#xff0c;在该范式中&#xff0c;Spark应用程序在驱动程序调用“ Action”之前不会执行任何操作。 惰性…

scala本地调试_如何编写自己的Java / Scala调试器

scala本地调试在本文中&#xff0c;我们将探讨Java / Scala调试器的编写和工作方式。 诸如Windows的WinDbg或Linux / Unix的gdb之类的本机调试器通过操作系统直接提供给它们的钩子来获取其功能&#xff0c;以监视和操纵外部进程的状态。 JVM充当OS之上的抽象层&#xff0c;它提…

java content()_Java contentEquals() 方法

全屏Java contentEquals() 方法contentEquals() 方法用于将将此字符串与指定的 StringBuffer 比较。语法public boolean contentEquals(StringBuffer sb)参数sb -- 要与字符串比较的 StringBuffer。返回值如字符串与指定 StringBuffer 表示相同的字符序列&#xff0c;则返回 tr…

java 加法 溢出_StackOverflow热帖:Java整数相加溢出怎么办?Java8一步搞定~

阅读本文大概需要 2 分钟。作者&#xff1a;Aaron_涛问题在之前刷题的时候遇见一个问题&#xff0c;需要解决int相加后怎么判断是否溢出&#xff0c;如果溢出就返回Integer.MAX_VALUE解决方案JDK8已经帮我们实现了Math下&#xff0c;不得不说这个方法是在StackOverflow找到了的…

通过这5个简单的技巧减少GC开销

编写代码的五种简单方法&#xff0c;可提高内存效率&#xff0c;而无需花费更多时间或降低代码可读性 垃圾回收会为您的应用程序增加多少开销&#xff1f; 您可能不知道确切的数字&#xff0c;但您确实知道总有改进的余地。 尽管自动GC是最有效的过程&#xff0c;但是如果它过…

xml 数字签名 破解_JAVA中带有数字签名的XML安全性

xml 数字签名 破解介绍 如您所知&#xff0c;XML在我们的产品或项目开发中起着重要作用&#xff0c;并且从XML文档中我们收集了很多信息&#xff0c;并且我们可以对XML文件执行CRUD操作。 但是&#xff0c;关于如何确保XML文件中可用的数据是真实的以及数据来自受信任的可靠来源…

centos 远程安装java程序_centos7远程服务器中redis的安装与java连接

1.下载安装redis在远程服务器中你想下载的位置执行以下命令来下载redis文件到服务器中$ wget http://download.redis.io/releases/redis-4.0.9.tar.gz说明&#xff1a;$是指你的当前目录&#xff0c;不是命令的一部分&#xff0c;wget命令用来下载网上资源&#xff0c;后面的地…

内部简单二进制编码(SBE)

SBE是用于金融行业的非常快速的序列化库&#xff0c;在本博客中&#xff0c;我将介绍一些使其快速发展的设计选择。 序列化的全部目的是对消息进行编码和解码&#xff0c;并且有很多可用的选项&#xff0c;从XML&#xff0c;JSON&#xff0c;Protobufer&#xff0c;Thrift&…

mingw64 下 java_在 Windows 10 64 位下安装 Mingw-w64

1、MinGW 的全称是&#xff1a;Minimalist GNU on Windows 。打开网址&#xff1a;http://www.mingw-w64.org/doku.php/download &#xff0c;选择 MingW-W64-builds。如图1图12、下载包名&#xff1a;mingw-w64-install.exe。安装时报错&#xff1a;Cannot download repositor…

java实现layui分页_layui如何实现数据分页功能

我们先来看下官网的演示画面。具体代码&#xff1a;页面引入layui.css、 layui.js前台jsvar limitcount 10;var curnum 1;//列表查询方法function productsearch(productGroupId,start,limitsize) {layui.use([table,laypage,laydate], function(){var table layui.table,la…

java 正则表达式使用_如何用正则表达式杀死Java

java 正则表达式使用我们最近偶然发现了一个我们绝对不了解的现象&#xff1a;您可以使用简单的正则表达式杀死任何Java IDE以及任何Java进程… 回到大学后&#xff0c;我被告知正则表达式&#xff08;称为正则语法或3型语法&#xff09;总是以有限状态的自动机结束&#xff0…

java 合并到一行_mysql中将多行数据合并成一行数据

一个字段可能对应多条数据&#xff0c;用mysql实现将多行数据合并成一行数据例如&#xff1a;一个活动id(activeId)对应多个模块名(modelName),按照一般的sql语句&#xff1a;1 SELECT am.activeId,m.modelName2 FROM activemodel am3 JOIN model m4 ON am.modelId m.modelId5…

容器化Spring Data Cassandra应用程序

我正在继续学习Docker的旅程。 在这一点上&#xff0c;我仍然保持简单。 这次&#xff0c;我将解决将Spring和Cassandra应用程序转换为使用容器而不是在主机上本地运行的问题。 更准确地说&#xff0c;使用Spring Data Cassandra整理应用程序。 我希望我前几天看过进行此更改。…

最快的 java 图像_ImageJ 1.53 世界上最快的Java图像处理程序

ImageJ 1.53 世界上最快的Java图像处理程序 已通过小编安装运行测试 100%可以使用。ImageJ 1.53 是世界上最快的纯Java图像处理程序。它可以在0.1秒内过滤2048x2048图像。每秒可以处理4000万像素的图片。ImageJ支持处理8位灰度或索引颜色&#xff0c;16位无符号整数&#xff0c…

java字节码提取if语句_终于找到了!有了它你就可以读懂字节码了!

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼0x80 ior 将栈顶两int型数值作“按位或”并将结果压入栈顶0x81 lor 将栈顶两long型数值作“按位或”并将结果压入栈顶0x82 ixor 将栈顶两int型数值作“按位异或”并将结果压入栈顶0x83 lxor 将栈顶两long型数值作“按位异或”并将结…

maven设置代理服务器_使用Maven设置您的应用服务器

maven设置代理服务器在许多情况下&#xff0c;无需事先设置应用程序就无法部署应用程序。 在JBoss AS 7.x中&#xff0c;您可能需要配置例如数据库连接。 或者&#xff0c;您必须配置一个安全领域。 也许您还想调整SLSB池…在任何情况下&#xff0c;团队中的所有开发人员都必须…

java编程中的di是什么_java-在Spring IoC / DI中使用@Component注释对接口...

在Spring类中,通常使用Component注释接口,特别是对于某些Spring构造型注释&#xff1a;package org.springframework.stereotype;...Componentpublic interface Service {...}要么 &#xff1a;package org.springframework.boot.test.context;...Componentpublic interface Te…

使用React和Spring Boot构建一个简单的CRUD应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 React的设计使创建交互式UI变得轻松自如。 它的状态管理非常有效&#xff0c;并且仅在…

java初始化该字符串值_java字符串数组初始化和赋值

//一维数组String[] str new String[5]; //创建一个长度为5的String(字符串)型的一维数组String[] str new String[]{“”,””,””,””,””};String[] str {“”,””,””,””,””};String数组初始化区别首先应该明白java数组里面存的是对象的引用&#xff0c;所以必…

java 无法找到ant_Java-Ant需要tools.jar并且无法找到我

Java-Ant需要tools.jar并且无法找到我我将一个Java程序的开发环境放在一起&#xff0c;并且在第一次尝试使用Ant构建脚本后&#xff0c;出现了以下错误&#xff1a;Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-6-openjdk/lib/tools.jar虽然通往jdk的…