概述
在处理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及更高版本可用。
例如,我们可以使用Stream
的anyMatch()
方法进行不区分大小写的字符串搜索:
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上可用。点击这里查看。