不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:php-note.com  发布于:2022-06-05 19:27  分类:Java基础  编辑

先说明一下好处有哪些:

1、如果你想 new 一个空的 List 且 这个 List 以后也不会再添加元素(有大坑,看下面更新)

那么就用 Collections.emptyList() 好了。

new ArrayList() 或者 new LinkedList() 在创建的时候有会有初始大小,多少会占用一内存。

每次使用都new 一个空的list集合,浪费就积少成多,浪费就严重啦,就不好啦

2、为了编码的方便

比如说一个方法返回类型是List,当没有任何结果的时候,返回null,有结果的时候,返回list集合列表。

那样的话,调用这个方法的地方,就需要进行null判断。使用emptyList这样的方法,可以方便方法调用者。返回的就不会是null,省去重复代码。

但是,需要注意的地方:

这个空的集合是不能调用.add(),添加元素的。因为直接报异常。因为源码就是这么写的:直接抛异常。

哦,Collections里面没这么写,但是EmptyList继承了AbstractList这个抽象类,里面简单实现了部分集合框架的方法。

这里面的add方法最后调用的方法体,就是直接抛异常。

throw new UnsupportedOperationException();

这么解释add报异常就对啦。 

下面简单看下这个源码:

/**
 * Collections 类里面的方法如下,一步步往下看就是啦
 */
public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}
//。。。。。
/**
 * Collections 类里面的方法如下,一步步往下看就是啦
 */
public static final List EMPTY_LIST = new EmptyList<>();
//。。。。。
 /**
 * Collections里面的一个静态内部类
 */
private static class EmptyList<E> extends AbstractList<E> implements RandomAccess, Serializable {
    private static final long serialVersionUID = 8842843931221139166L;

    public Iterator<E> iterator() {
        return emptyIterator();
    }
    public ListIterator<E> listIterator() {
        return emptyListIterator();
    }

    public int size() {return 0;}
    public boolean isEmpty() {return true;}

    public boolean contains(Object obj) {return false;}
    public boolean containsAll(Collection<?> c) { return c.isEmpty(); }

    public Object[] toArray() { return new Object[0]; }

    public <T> T[] toArray(T[] a) {
        if (a.length > 0)
            a[0] = null;
        return a;
    }

    public E get(int index) {
        throw new IndexOutOfBoundsException("Index: "+index);
    }

    public boolean equals(Object o) {
        return (o instanceof List) && ((List<?>)o).isEmpty();
    }

    public int hashCode() { return 1; }

    // Preserves singleton property
    private Object readResolve() {
        return EMPTY_LIST;
    }
}

除了这个emptyList,之外,还有类似的,emptyMap,emptySet等等。具体看下图,都是一个套路。

看下面的代码,咱先弄个empty出来,然后,可能有需求要继续在这个空集合里面添加内容。那么,bug就来啦。

/**
 * 测试这个空集合是某个Java bean 的某个属性的时候的操作,也是不能add的
 */
private static void testModelEmptyField() {
    Car car = new Car();
    car.setBoys(Collections.emptyList());
    car.getBoys().add("sss");
}

/**
 * Collections.emptyMap()  返回的空集合是不能进行put的
 */
private static void testEmptyMap() {
    Map<String,String> map = Collections.emptyMap();
    for (Map.Entry<String, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ":"+ entry.getValue());
    }
    map.put("a","a");
    for (Map.Entry<String, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ":"+ entry.getValue());
    }
}

/**
 * Collections.emptyList()  返回的空集合是不能进行add的
 */
private static void testEmptyList() {
    List<String> list = Collections.emptyList();
    for (String s : list) {
        System.out.println(s);
    }
    //异常
    list.add("1");
    for (String s : list) {
        System.out.println(s);
    }
}

具体出的bug,看下面的截图。

阿弥陀佛,算了 ,这个咱还是不用了吧。

很危险的,分分钟代码就bug啦。这个不好,不好。。。不用啦,了解下就得啦。

为什么不推荐使用:

因为这个是返回了个默认集合,这个集合不是null了,其他人在使用你这个返回值的时候,省去了判断null这一步。

假设,这有个接盘的老铁,一看,哎这个方法始终都是返回一个集合的,那么万一需求变了,要是空集合的时候,给这个空集合添加个默认值,或者怎么滴,反正,就是有进一步的操作,要往这个返回的集合里面添加东西。那么,在这个接盘的老铁写代码的阶段,这个代码是不会报错的。代码看上去一切OK,但是,一旦,项目运行,这个代码运行了,就会出现我最后一个图的,异常了。要是这个老铁是个新人或者说不了解,你这个“高级装逼”操作的返回集合有这个问题的话,打死他,他也不知道,他这个异常问题,出在哪里。

 

 

摘自:Java之Collections.emptyList()、emptySet()、emptyMap()的作用和好处以及要注意的地方

 




自己创建一个工具类

package com.wanma.framework_web.helper;

import java.util.*;

/**
 * 空实例 助手类
 */
public class EmptyHelper {
    /**
     * 返回空的ArrayList实例
     */
    public static <T> ArrayList<T> emptyArrayList() {
        return new ArrayList<>();
    }

    /**
     * 返回空的LinkedList实例
     */
    public static <T> LinkedList<T> emptyLinkedList() {
        return new LinkedList<>();
    }

    /**
     * 返回空的HashSet实例
     */
    public static <T> HashSet<T> emptyHashSet() {
        return new HashSet<>();
    }

    /**
     * 返回空的LinkedHashSet实例
     */
    public static <T> LinkedHashSet<T> emptyLinkedHashSet() {
        return new LinkedHashSet<>();
    }

    /**
     * 返回空的HashMap实例
     */
    public static <K, V> HashMap<K, V> emptyHashMap() {
        return new HashMap<>();
    }

    /**
     * 返回空的LinkedHashMap实例
     */
    public static <K, V> LinkedHashMap<K, V> emptyLinkedHashMap() {
        return new LinkedHashMap<>();
    }
}

使用示例:

/**
 * 获取角色的模块Ids
 */
@Override
public List<Integer> getRoleModuleIds(int roleId) {
	if (roleId <= 0) {
		return EmptyHelper.emptyArrayList();
	}
	
	// ......
}