慎用Java Collection的contains函数

背景

最近碰到一个坑,看代码:

    @Test
    public void should_can_get_true_when_given_matched_type() {
        List numberList = Lists.newArrayList(1, 2, 34, 4);

        Boolean contain = numberList.contains(2);

        assertThat(contain).isTrue();
    }

    @Test
    public void should_can_get_false_when_given_not_matched_type() {
        List numberList = Lists.newArrayList(1, 2, 34, 4);

        Boolean contain = numberList.contains(2L);// List 去判断 Long 类型元素

        assertThat(contain).isFalse();
    }

这里更改了待判断参数类型,并不报错,只是返回 false。

原因

以ArrayList 为例,发现源码如下:

    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

而对于包装类型,复写了equals方法

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

也就是说,对于同类型的对象,才去比较值来判断是否“相等”。

改进


有些集合的原生函数不建议使用,比如Collections.contains/remove/Object.equals等。


改进一

@Component
public class MyCollectionUtils {
    public Boolean contained(Collection collection, T element) {
        return collection.contains(element);
    }
}

使用时,明确指定要检测的元素类型。

    @Autowired
    private MyCollectionUtils myCollectionUtilsInteger;// 对集合和待检查元素都校验类型
    
    @Autowired
    private MyCollectionUtils myCollectionUtilsString;

    @Test
    public void should_can_get() {
        Boolean result = myCollectionUtilsInteger.contained(Lists.newArrayList(1, 2, 34, 4), 2);

        assertThat(result).isTrue();
    }

    @Test
    public void should_can_get2() {
        Boolean result = myCollectionUtilsString.contained(Lists.newArrayList("2", "s", "s", "333"), "2");

        assertThat(result).isTrue();
    }

每次根据需要注入不同类型的校验工具对象,检查性很强,不过这样做也有缺点,就是不同类型时,产生多个对象。

改进二

代码差不多,只不过只作为一个静态函数而已。

public class MyCollectionUtils {
    public static  Boolean contains(Collection collection, T element) {
        return collection.contains(element);
    }
}

使用时,如果类型不一致,编译报错。

    @Test
    public void should_compile_error_when_given_un_matched_type() {
        List numberList = Lists.newArrayList(1, 2, 34, 4);

        // MyCollectionUtils.contains(numberList, 2L);
        // 类型不一致,直接编译错误
    }

 

你可能感兴趣的:(Java)