灵魂拷问:如何检查Java数组中是否包含某个值 ?(1)-阿里云开发者社区

开发者社区> 沉默王二> 正文

灵魂拷问:如何检查Java数组中是否包含某个值 ?(1)

简介: 灵魂拷问:如何检查Java数组中是否包含某个值 ?
+关注继续查看

在逛 programcreek 的时候,我发现了一些专注细节但价值连城的主题。比如说:如何检查Java数组中是否包含某个值 ?像这类灵魂拷问的主题,非常值得深入地研究一下。


另外,我想要告诉大家的是,作为程序员,我们千万不要轻视这些基础的知识点。因为基础的知识点是各种上层技术共同的基础,只有彻底地掌握了这些基础知识点,才能更好地理解程序的运行原理,做出更优化的产品。


我曾在某个技术论坛上分享过一篇非常基础的文章,结果遭到了无数的嘲讽:“这么水的文章不值得分享。”我点开他的头像进入他的主页,发现他从来没有分享过一篇文章,不过倒是在别人的博客下面留下过不少的足迹,大多数都是冷嘲热讽。我就纳闷了,技术人不都应该像我这样低调谦逊吗?怎么戾气这么重!


好了,让我们来步入正题。如何检查数组(未排序)中是否包含某个值 ?这是一个非常有用并且经常使用的操作。我想大家的脑海中应该已经浮现出来了几种解决方案,这些方案的时间复杂度可能大不相同。


我先来提供四种不同的方法,大家看看是否高效。


1)使用 List


public static boolean useList(String[] arr, String targetValue) {
    return Arrays.asList(arr).contains(targetValue);
}
Arrays 类中有一个内部类 ArrayList(可以通过 Arrays.asList(arr) 创建该实例),其 contains() 方法的源码如下所示。
public boolean contains(Object o) {
    return indexOf(o) != -1;
}
public int indexOf(Object o) {
    E[] a = this.a;
    if (o == null) {
        for (int i = 0; i < a.length; i++)
            if (a[i] == null)
                return i;
    } else {
        for (int i = 0; i < a.length; i++)
            if (o.equals(a[i]))
                return i;
    }
    return -1;
}


从上面的源码可以看得出,contains() 方法调用了 indexOf() 方法,如果返回 -1 则表示 ArrayList 中不包含指定的元素,否则就包含。其中 indexOf() 方法用来获取元素在 ArrayList 中的下标,如果元素为 null,则使用“==”操作符进行判断,否则使用 equals() 方法进行判断。


PS:关于“==”操作符和 equals() 方法,可以参照我另外一篇文章《如何比较 Java 的字符串?》


2)使用 Set


public static boolean useSet(String[] arr, String targetValue) {
    Set<String> set = new HashSet<String>(Arrays.asList(arr));
    return set.contains(targetValue);
}


HashSet 其实是通过 HashMap 实现的,当使用 new HashSet<String>(Arrays.asList(arr)) 创建并初始化了 HashSet 对象后,其实是在 HashMap 的键中放入了数组的值,只不过 HashMap 的值为默认的一个摆设对象。大家感兴趣的话,可以查看一下 HashSet 的源码。


我们来着重看一下 HashSet 的 contains() 方法的源码。


public boolean contains(Object o) {

   return map.containsKey(o);

}


public boolean containsKey(Object key) {

   return getNode(hash(key), key) != null;

}


从上面的源码可以看得出,contains() 方法调用了 HashMap 的 containsKey() 方法,如果指定的元素在 HashMap 的键中,则返回 true;否则返回 false。


3)使用一个简单的循环


public static boolean useLoop(String[] arr, String targetValue) {

   for (String s : arr) {

       if (s.equals(targetValue))

           return true;

   }

   return false;

}


for-each 循环中使用了 equals() 方法进行判断——这段代码让我想起了几个词,分别是简约、高效、清晰。


4)使用 Arrays.binarySearch()


public static boolean useArraysBinarySearch(String[] arr, String targetValue) {
    int a = Arrays.binarySearch(arr, targetValue);
    if (a > 0)
        return true;
    else
        return false;
}


不过,binarySearch() 只适合查找已经排序过的数组。


由于我们不确定数组是否已经排序过,所以我们先来比较一下前三种方法的时间复杂度。由于调用 1 次的时间太短,没有统计意义,我们就模拟调用 100000 次,具体的测试代码如下所示。


String[] arr = new String[]{"沉", "默", "王", "二", "真牛逼"};
// 使用 List
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
    useList(arr, "真牛逼");
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("useList:  " + duration / 1000000);
// 使用 Set
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
    useSet(arr, "真牛逼");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useSet:  " + duration / 1000000);
// 使用一个简单的循环
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
    useLoop(arr, "真牛逼");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useLoop:  " + duration / 1000000);


PS:nanoTime() 获取的是纳秒级,这样计算的时间就更精确,最后除以 1000000 就是毫秒。换算单位是这样的:1秒=1000毫秒,1毫秒=1000微秒,1微秒=1000纳秒。


统计结果如下所示:


useList:  6

useSet:  40

useLoop:  2



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
JDK 的安装与配置|学习笔记
快速学习 JDK 的安装与配置
8 0
第一个 Java 程序|学习笔记
快速学习 第一个 Java 程序
5 0
方法的定义与使用(方法递归调用)|学习笔记
快速学习 方法的定义与使用(方法递归调用)
4 0
程序逻辑控制(循环控制)|学习笔记
快速学习 程序逻辑控制(循环控制)
4 0
方法的定义与使用(方法重载)|学习笔记
快速学习 方法的定义与使用(方法重载)
5 0
程序逻辑控制(分支结构)|学习笔记
快速学习 程序逻辑控制(分支结构)
6 0
程序逻辑控制(循环结构)|学习笔记
快速学习 程序逻辑控制(循环结构)
6 0
10S
冬季实战营第一期:从零到一上手玩转云服务器的学习报告
训练营日期:2022年1月17日 - 2022年1月23日,通过前五日从零学习云服务器,还能领取限量版盲盒等奖品
5 0
解决Java- 错误: 找不到或无法加载主类 HelloWorld.java
针对初学者使用javac,java等命令编译class文件时出现的经典问题,提供解决思路和方法。
7 0
“冬季实战营第一期”之从零到一上手玩转云服务器——学习报告
动手实战、专家带练。由浅及深,逐渐提升动手实操能力。
18 0
+关注
沉默王二
微信搜索「沉默王二」,回复关键字「00」获取硬核计算机基础资料。
1084
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载