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

网友投稿 249 2022-12-04

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

目录双括号语法初始化集合不建议使用这种形式替代方案使用Arrays工具类使用Stream使用第三方工具类java 9内置方法

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

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

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

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

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

Set users = nhttp://ew 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() http://{{

add("Hollis");

add("hollis");

add("HollisChuang");

add("hollis666");

}};

}

}

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

Map 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://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://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 list2 = Arrays.asList("hollis ", "Hollis", "HollisChuang");

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

使用StreMYnCmam

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

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

List 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 Unmodifiable Lists for details.

*

* @param the {@code List}'s element type

* @return an empty {@code List}

*

* @since 9

*/

static List of() {

return ImmutableCollections.emptyList();

}

static List of(E e1) {

return new ImmutableCollections.List12<>(e1);

}

static List 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);

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java并发编程之threadLocal
下一篇:SpringMVC @NotNull校验不生效的解决方案
相关文章

 发表评论

暂时没有评论,来抢沙发吧~