概述

在处理ArrayList时,查找列表中的元素是一项基本操作。contains()方法帮助我们判断一个列表对象是否包含我们正在寻找的元素。

在这个教程中,我们将探讨如何在ArrayList<String>对象中进行不区分大小写的字符串搜索。

2. 问题介绍

内部地,ArrayList.contains()方法使用equals()方法来确定列表是否包含给定的元素。如果ArrayList的所有元素都是字符串(即在处理ArrayList<String>时),contains()方法会进行区分大小写的字符串搜索。让我们通过一个例子快速理解这一点。

假设我们有一个包含六个字符串的列表:

List<String> LANGUAGES = Arrays.asList("Java", "Python", "Kotlin", "Ruby", "Javascript", "Go");

当我们检查LANGUAGES是否包含"jAvA"时,contains()方法报告为false,因为"jAvA"并不等于"Java"

String searchStr = "jAvA";
boolean result = LANGUAGES.contains(searchStr);
assertFalse(result);

在这个教程中,我们将学习几种方法,在不考虑大小写的情况下在ArrayList<String>实例中搜索字符串。为了简化,我们将使用单元测试断言来验证解决方案是否按预期工作。

接下来,让我们实际操作一下。

3. 使用Stream API

Java的流API提供了许多便捷的接口,使我们可以轻松地以流的方式处理集合。它在Java 8及更高版本可用。

例如,我们可以使用StreamanyMatch()方法进行不区分大小写的字符串搜索:

String searchStr = "koTliN";
boolean result = LANGUAGES.stream().anyMatch(searchStr::equalsIgnoreCase);
assertTrue(result);

如上例所示,我们在LANGUAGES列表中搜索字符串"koTliN"。运行后,测试通过。

值得注意的是,我们传递给anyMatch()方法的searchStr::equalsIgnoreCase是一个方法引用。对于流中的每个字符串元素,都会调用searchStr.equalsIgnoreCase()方法。

4. 创建辅助方法

我们已经看到,流API可以简单地解决这个问题。然而,如果我们使用的Java版本低于8,就不能使用流API。在这种情况下,解决问题的经典方法是创建一个辅助方法:

public class IgnoreCaseSearchUtil {
    public static boolean ignoreCaseContains(List<String> theList, String searchStr) {
        for (String s : theList) {
            if (searchStr.equalsIgnoreCase(s)) {
                return true;
            }
        }
        return false;
    }
}

如上述代码所示,我们在给定列表中的每个字符串元素上使用一个for循环进行检查。一旦元素与searchStr不区分大小写相等,方法立即返回true,而无需检查列表中的其他元素。

接下来,让我们创建一个测试来验证其功能:

String searchStr = "ruBY";
boolean result = IgnoreCaseSearchUtil.ignoreCaseContains(LANGUAGES, searchStr);
assertTrue(result);

这次我们在列表中搜索字符串"ruBY"。同样,如果运行测试,它会通过。

5. 创建ArrayList<String>的子类

到目前为止,我们学习了两种在不考虑大小写的情况下判断ArrayList<String>对象是否包含给定字符串的方法。这两种解决方案都很容易理解。然而,如果在项目中频繁执行此操作,我们需要多次调用辅助方法或流API的anyMatch()方法。

如果情况如此,我们可能希望创建一个特定的ArrayList<String>类型,该类型原生支持忽略大小写的contains()方法。

接下来,让我们创建一个ArrayList<String>的子类:

public class IgnoreCaseStringList extends ArrayList<String> {

    public IgnoreCaseStringList() {

    }

    public IgnoreCaseStringList(Collection<? extends String> c) {
        super(c);
    }

    @Override
    public boolean contains(Object o) {
        String searchStr = (String) o;
        for (String s : this) {
            if (searchStr.equalsIgnoreCase(s)) {
                return true;
            }
        }
        return false;
    }

}

如上代码所示,IgnoreCaseStringList类继承自ArrayList<String>。我们创建了两个构造函数,以便更轻松地初始化IgnoreCaseStringList实例。此外,为了使IgnoreCaseStringList支持不区分大小写的contains()方法,我们重写了该方法。实现对我们来说并不陌生,它与我们学到的辅助方法非常相似。

接下来,让我们测试IgnoreCaseStringList是否正常工作:

String searchStr = "pYtHoN";
List<String> ignoreCaseList = new IgnoreCaseStringList(LANGUAGES);
boolean result = ignoreCaseList.contains(searchStr);
assertTrue(result);

如我们所见,初始化一个IgnoreCaseList实例后,我们可以直接调用contains()方法进行不区分大小写的搜索。当运行上面的测试时,它通过了。所以,IgnoreCaseStringList很好地完成了工作。

值得一提的是,IgnoreCaseList方法还带来了一个好处:它也使containsAll()方法变为区分大小写的。这是因为containsAll()方法在ArrayList的超类型AbstractCollection类中实现,它内部调用了contains()方法:

public boolean containsAll(Collection<?> c) {
    Iterator var2 = c.iterator();
    Object e;
    do {
        if (!var2.hasNext()) {
            return true;
        }
        e = var2.next();
    } while(this.contains(e));
    return false;
}

最后,让我们编写一个测试来验证这一点:

boolean resultContainAll = ignoreCaseList.containsAll(Arrays.asList("pYtHon", "jAvA", "koTliN", "ruBY"));
assertTrue(resultContainAll);

另一方面,如果我们希望流API和辅助方法方法也支持区分大小写的containsAll()功能,我们必须自己实现,例如,通过添加另一个辅助方法。

6. 总结

在这篇文章中,我们探讨了如何在ArrayList<String>中进行不区分大小写的搜索。我们通过示例学习了解决问题的三种方法。

如往常一样,文章中展示的所有代码片段都在GitHub上可用。点击这里查看