Java怎样创建集合才能避免造成内存泄漏你了解吗

 更新时间:2021年09月29日 08:46:42   作者:Hollis Chuang  
内存泄漏是指无用对象持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏。长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收

由于Java语言的集合框架中(collections, 如list, map, set等)没有提供任何简便的语法结构,这使得在建立常量集合时的工作非常繁索。每次建立时我们都要做:

1、定义一个空的集合类变量

2、向这个结合类中逐一添加元素

3、将集合做为参数传递给方法

例如,要将一个Set变量传给一个方法:

Set users = new HashSet();
users.add("Hollis");
users.add("hollis");
users.add("HollisChuang");
users.add("hollis666");
transferUsers(users);

这样的写法稍微有些复杂,有没有简洁的方式呢?

双括号语法初始化集合

其实有一个比较简洁的方式,那就是双括号语法(double-brace syntax)建立并初始化一个新的集合:

public class DoubleBraceTest {
    public static void main(String[] args) {
        Set users = new HashSet() {{
            add("Hollis");
            add("hollis");
            add("HollisChuang");
            add("hollis666");
        }};
    }
}

同理,创建并初始化一个HashMap的语法如下:

Map<String,String> users = new HashMap<>() {{
    put("Hollis","Hollis");
    put("hollis","hollis");
    put("HollisChuang","HollisChuang");
}};

不只是Set、Map,jdk中的集合类都可以用这种方式创建并初始化。

当我们使用这种双括号语法初始化集合类的时候,在对Java文件进行编译时,可以发现一个奇怪的现象,使用javac对DoubleBraceTest进行编译:

javac DoubleBraceTest.java

我们会发现,得到两个class文件:

DoubleBraceTest.class
DoubleBraceTest$1.class

有经验的朋友可能一看到这两个文件就会知道,这里面一定用到了匿名内部类。

没错,使用这个双括号初始化的效果是创建匿名内部类。创建的类有一个隐式的this指针指向外部类。

不建议使用这种形式

首先,使用这种形式创建并初始化集合会导致很多内部类被创建。因为每次使用双大括号初始化时,都会生成一个新类。如这个例子:

Map hollis = new HashMap(){{
    put("firstName", "Hollis");
    put("lastName", "Chuang");
    put("contacts", new HashMap(){{
        put("0", new HashMap(){{
            put("blogs", "http://www.hollischuang.com");
        }});
        put("1", new HashMap(){{
            put("wechat", "hollischuang");
        }});
    }});
}};

这会使得很多内部类被创建出来:

DoubleBraceTest$1$1$1.class
DoubleBraceTest$1$1$2.class
DoubleBraceTest$1$1.class
DoubleBraceTest$1.class
DoubleBraceTest.class

这些内部类被创建出来,是需要被类加载器加载的,这就带来了一些额外的开销。

如果您使用上面的代码在一个方法中创建并初始化一个map,并从方法返回该map,那么该方法的调用者可能会毫不知情地持有一个无法进行垃圾收集的资源。

public Map getMap() {
    Map hollis = new HashMap(){{
        put("firstName", "Hollis");
        put("lastName", "Chuang");
        put("contacts", new HashMap(){{
            put("0", new HashMap(){{
                put("blogs", "http://www.hollischuang.com");
            }});
            put("1", new HashMap(){{
                put("wechat", "hollischuang");
            }});
        }});
    }};

    return hollis;
}

我们尝试通过调用getMap得到这样一个通过双括号初始化出来的map

public class DoubleBraceTest {
    public static void main(String[] args) {
        DoubleBraceTest doubleBraceTest = new DoubleBraceTest();
        Map map = doubleBraceTest.getMap();
    }
}

返回的Map现在将包含一个对DoubleBraceTest的实例的引用。读者可以尝试这通过debug或者以下方式确认这一事实。

Field field = map.getClass().getDeclaredField("this$0");
field.setAccessible(true);
System.out.println(field.get(map).getClass());

替代方案

很多人使用双括号初始化集合,主要是因为他比较方便,可以在定义集合的同时对他进行初始化。

但其实,目前已经有很多方案可以做这个事情了,不需要再使用这种存在风险的方案。

使用Arrays工具类

当我们想要初始化一个List的时候,可以借助Arrays类,Arrays中提供了asList可以把一个数组转换成List:

List<String> list2 = Arrays.asList("hollis ", "Hollis", "HollisChuang");

但是需要注意的是,asList 得到的只是一个 Arrays 的内部类,是一个原来数组的视图 List,因此如果对它进行增删操作会报错。

使用Stream

Stream是Java中提供的新特性,他可以对传入流内部的元素进行筛选、排序、聚合等中间操作(intermediate operate),最后由最终操作(terminal operation)得到前面处理的结果。

我们可以借助Stream来初始化集合:

List<String> list1 = Stream.of("hollis", "Hollis", "HollisChuang").collect(Collectors.toList());

使用第三方工具类

很多第三方的集合工具类可以实现这个功能,如Guava等:

ImmutableMap.of("k1", "v1", "k2", "v2");
ImmutableList.of("a", "b", "c", "d");

关于Guava和其中定义的不可变集合,我们在后面会详细介绍

Java 9内置方法

其实在Java 9 中,在List、Map等集合类中已经内置了初始化的方法,如List中包含了12个重载的of方法,就是来做这个事情的:

/**
 * Returns an unmodifiable list containing zero elements.
 *
 * See <a href="#unmodifiable" rel="external nofollow" >Unmodifiable Lists</a> for details.
 *
 * @param <E> the {@code List}'s element type
 * @return an empty {@code List}
 *
 * @since 9
 */
static <E> List<E> of() {
    return ImmutableCollections.emptyList();
}

static <E> List<E> of(E e1) {
    return new ImmutableCollections.List12<>(e1);
}

static <E> List<E> of(E... elements) {
    switch (elements.length) { // implicit null check of elements
        case 0:
            return ImmutableCollections.emptyList();
        case 1:
            return new ImmutableCollections.List12<>(elements[0]);
        case 2:
            return new ImmutableCollections.List12<>(elements[0], elements[1]);
        default:
            return new ImmutableCollections.ListN<>(elements);
    }
}

到此这篇关于Java怎样创建集合才能避免造成内存泄漏你了解吗的文章就介绍到这了,更多相关Java 集合内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot实现单文件与多文件上传

    SpringBoot实现单文件与多文件上传

    本次例子不基于第三方存储(如七牛云对象存储、阿里云对象存储、腾讯云对象存储等),仅基于本地存储。本文主要内容如下:公共文件存储代码;单文件上传代码;多文件上传代码
    2021-05-05
  • java使用poi在excel单元格添加超链接设置字体颜色的方法

    java使用poi在excel单元格添加超链接设置字体颜色的方法

    这篇文章主要介绍了java使用poi在excel单元格添加超链接,设置字体颜色,poi功能还是很强大的,基本能想到的功能都能通过poi实现,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • 详解JVM系列之对象的锁状态和同步

    详解JVM系列之对象的锁状态和同步

    锁和同步是java多线程编程中非常常见的使用场景。为了锁定多线程共享的对象,Java需要提供一定的机制来实现共享对象的锁定。当第二个线程进入同一个区域的时候,必须等待第一个线程解锁该对象。JVM是怎么做到的呢?快来一起看看吧。
    2021-06-06
  • Java Calendar类使用案例详解

    Java Calendar类使用案例详解

    这篇文章主要介绍了Java Calendar类使用案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 浅谈Java中向上造型向下造型和接口回调中的问题

    浅谈Java中向上造型向下造型和接口回调中的问题

    这篇文章主要介绍了浅谈Java中向上造型向下造型和接口回调中的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Spring MVC和springboot静态资源处理问题

    Spring MVC和springboot静态资源处理问题

    这篇文章主要介绍了Spring MVC和springboot静态资源处理问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 例题详解Java dfs与记忆化搜索和分治递归算法的使用

    例题详解Java dfs与记忆化搜索和分治递归算法的使用

    递归指函数调用自身。常用的递归算法有dfs(深度优先搜索)、记忆化搜索和分治,接下来将用几个算法题来带你熟练掌握它
    2022-04-04
  • Java 详解Collection集合之ArrayList和HashSet

    Java 详解Collection集合之ArrayList和HashSet

    本章具体介绍了ArrayList和HashSet两种集合的基本使用方法和区别,图解穿插代码实现。 JAVA成仙路从基础开始讲,后续会讲到JAVA高级,中间会穿插面试题和项目实战,希望能给大家带来帮助
    2022-03-03
  • Java实现走迷宫回溯算法

    Java实现走迷宫回溯算法

    这篇文章主要为大家详细介绍了Java实现走迷宫回溯算法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • JAVA实现 SpringMVC方式的微信接入、实现简单的自动回复功能

    JAVA实现 SpringMVC方式的微信接入、实现简单的自动回复功能

    这篇文章主要介绍了JAVA实现 SpringMVC方式的微信接入、实现简单的自动回复功能的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-11-11

最新评论