慎用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 =https://www.it610.com/article/= ((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 Collection的contains函数】

    推荐阅读