【Java】Java编程问题top100---基础语法系列(二)

文章详细讨论了Java中测试数组是否包含特定值的不同方法,包括使用Arrays.asList、ApacheCommonsLang的ArrayUtils以及JDK8和9的API。还提到了重写equals和hashCode方法时的理论和实践注意事项,以及如何从多层循环中跳出。此外,还介绍了将String转换为Int的方法和split字符串的用法,强调了异常处理和正则表达式的重要性。
摘要由CSDN通过智能技术生成


感觉github上的翻译质量并没有想象中的那么好,感谢前辈的努力,但是还是得自力更生一步一步看国外文章自己动手翻译整合,码字不易,点赞支持~
萌新须知:平时写代码要老老实实判空,毕竟平时都是共同开发,不是你一个人单干,万一哪天对方改代码了,你调人家方法,返回个null给你,你也得背锅,另外不建议用assert断言,生产环境会关掉assert的。

六、如何测试一个数组是否包含指定的值?

指定数组,如:

    public static final String[] VALUES = new String[]{"id", "name", "location"};

有哪些比较好的方式,判断这个数组 VALUES 是否包含值id?

简单且优雅的方法:

  1. Arrays.asList(…).contains(…)

  2. 使用 Apache Commons Lang包中的ArrayUtils.contains(需要先引入Maven)

pom.xml

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.11</version>
        </dependency>
import org.apache.commons.lang3.ArrayUtils;

// 测试一个数组是否包含指定的值
public class test01 {
    public static final String[] VALUES = new String[]{"id", "name", "location"};

    public static void main(String[] args) {
        if (ArrayUtils.contains(VALUES, "id")) {
            System.out.println("Contain");
        } else {
            System.out.println("Does Not Contain");
        }
    }
}

自己动手写逻辑

其实本质就是一个查找问题,即查找一个数组是否包含某个值。对于原始类型,若是无序的数组,可以直接写一个 for 循环:

import java.util.Objects;
    // 无序数组
    public static boolean useLoop(String[] arr, String targetValue) {
        for (String s : arr) {
            // if (s.equals(targetValue)) {//不推荐这样用,以避免s为null,会不安全,改为下面这种
            if (Objects.equals(s,targetValue)) {
                return true;
            }
        }
        return false;
    }

若是有序的数组,可以考虑二分查找或者其他查找算法:

import java.util.Arrays;
    // 有序数组
    public static boolean useArraysBinarySearch(String[] arr, String targetValue) {
        int a = Arrays.binarySearch(arr, targetValue);
        if (a >= 0) {
            return true;
        } else {
            return false;
        }
    }

对象数组

若数组里包含的是一个个对象,实际上比较就是引用是否相等(String 类型是判断值是否相等),本质就是比较 hashcode 和 equal 方法,可以考虑使用 List 或者 Set,如下:

    public static boolean useList(String[] arr, String targetValue) {
        return Arrays.asList(arr).contains(targetValue);
    }

JDK 8 API

jdk 8及之后的jdk版本可以使用Streams

    // 使用Streams
    public static void useStreams(String[] arr, String targetValue) {
        if (Arrays.stream(VALUES).anyMatch("id"::equals)) {
            System.out.println("Contain");
        } else {
            System.out.println("Does Not Contain");
        }
    }

要检查是不是int ,或double的数组或者long包含值IntStream,请分别使用 ,DoubleStream或LongStream。

举个int的例子

    int[] a = {1,2,3,4};
    if(IntStream.of(a).anyMatch(x -> x == 4)){
        System.out.println("Contain");
    } else {
        System.out.println("Does Not Contain");
    }

JDK 9 API Set.of()

再三提示,jdk9,jdk9,jdk9。jdk 9及之后的jdk版本可以使用Set.of
jdk8的别凑热闹,不过可以知道下这个知识点,但这数据量太少,效率不高。

// 测试一个数组是否包含指定的值
public class test01 {
    private static final Set<String> VALUES = Set.of(
            "id", "name", "location"
    );
    
    public static boolean useSet(String[] arr) {
        if (VALUES.contains(s)) {
            System.out.println("Contain");
        } else {
            System.out.println("Does Not Contain");
        }
    }
}

O(1),很简洁、很漂亮~(就是开发用的JDK8用不上hh)

补充
如果数组数据量非常大,还经常使用查找的话,一般方法是O(n)线性查找,可以改用map系列。
map集合有三个常见的实现类:HashMap,TreeMap,LinkedHashMap。
TreeMap基于红黑树(一种自平衡二叉查找树)实现的,时间复杂度平均能达到O(log n)。
HashMap是基于散列表实现的,时间复杂度平均能达到O(1)。正常是O(1)到O(n)jdk1.8添加了 红黑树 是 O(log n)
TreeMap的get操作的时间复杂度是O(log(n))的,相比于HashMap的O(1)还是差不少的。
LinkedHashMap的出现就是为了平衡这些因素,能以O(1)时间复杂度查找元素,又能够保证key的有序性
为了更安全,不让修改的话,上这个Collections.unmodifiableSet,一旦修改就会报错。

    /* 
    Set<String> set = new HashSet<String>();
    set.add("id");
    set.add("name");
    set.add("location");
    Set unmodset = Collections.unmodifiableSet(set);
    unmodset.add("Hello");//编译运行会报错
    */

七、重写(Override)equlas和hashCode方法时应考虑的问题

理论上讲(编程语言、数学层面)

equals() 定义了对象的相等关系(自反性、对称性、传递性) 。
另外,它还具有一致性(如果一个对象没有修改,那么对象的equals方法,应总是返回相同的值),此外,o.equals(null)应当总是返回false。
hashCode()也必须具备一致性的(如果equal的结果没有变,那么hashcode()也应总是返回相同的值)

总的来说,这两个方法的关系:

假如a.equals(b),那么a.hashCode() 应等于b.hashCode()

实践上讲

如果你重写了其中一个方法,那么务必重写另外一个方法

equals()和hashCode()所计算的属性集(set of fields)应当是一样的
如何更快地重写这两个方法呢?

  1. 使用Apache Commons Lang library中的EqualsBuilderHashCodeBuilder
public class Person {
    private String name;
    private int age;
    // ...

    public int hashCode() {
        return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
            // if deriving: appendSuper(super.hashCode()).
            append(name).
            append(age).
            toHashCode();
        // 我感觉IDEA直接生成的这个也不错
        // return Objects.hash(name, age);
    }

    public boolean equals(Object obj) {
       if (!(obj instanceof Person))
            return false;
        if (obj == this)
            return true;

        Person rhs = (Person) obj;
        return new EqualsBuilder().
            // if deriving: appendSuper(super.equals(obj)).
            append(name, rhs.name).
            append(age, rhs.age).
            isEquals();
            
        // 我感觉IDEA直接生成的这个也不错
        // return age == person.age && Objects.equals(name, person.name);
    }
}
  1. 代码编辑区右键,然后
    (idea)选择 Generate… > equals() and hashCode()
    (eclipse)选择 Source > Generate hashCode() and equals()

另外请记得

当你使用一些基于Hash的 Collection 、 Map,例如HashSet, LinkedHashSet, HashMap, Hashtable, 、WeakHashMap等。在键值对被放到集合中之后,请确保其key值所对应的hashCode()是保持不变的。比较可靠的一个办法,是保持这些key是不可变的,这也能带来不少好处

八、从一个多层嵌套循环中直接跳出

问题:
Java中如何从一个多层嵌套循环中退出,例如下面,有两个循环,break只能退出一个for循环,不能直接跳过第二个for循环

for (Type type : types) {  
    for (Type t : types2) {  
         if (some condition) {  
             // Do something and break...  
             break; // 这样只退出了最里的for循环  
         }  
}}  

回答:
可以用break+label的语法,例子如下

public class Test03 {
    public static void main(String[] args) {
        outerloop:
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    break outerloop;
                }
                System.out.println(i + " " + j);
            }
        }
        System.out.println("Done");
    }
}

有一点要注意,break label的位置一定要在label代码块的内部。否则无效,语法错误。
首先在for循环前加标签,如例子中的outerloop,然后在for循环内break label(如本例的outerloop),就会跳出该label指定的for循环。

九、如何将String转换为Int

##如何将String转换为Int

有两种方式

        Integer x = Integer.valueOf(str);
        // or
        int y = Integer.parseInt(str);

这两种方式有一点点不同:

  • valueOf返回的是java.lang.Integer的实例
  • parseInt返回的是基本数据类型 int

Short.valueOf/parseShort,Long.valueOf/parseLong等也是有类似差别。

另外还需注意的是,在做int类型转换时,可能会抛出NumberFormatException,因此要做好异常捕获

public class Test04 {
    public static void test(String[] args) {
        int foo;
        String StringThatCouldBeANumberOrNot = "26263Hello"; //will throw exception
        String StringThatCouldBeANumberOrNot2 = "26263"; //will not throw exception
        try {
            foo = Integer.parseInt(StringThatCouldBeANumberOrNot);
        } catch (NumberFormatException e) {
            //Will Throw exception!
            //do something! anything to handle the exception.
        }

        try {
            foo = Integer.parseInt(StringThatCouldBeANumberOrNot2);
        } catch (NumberFormatException e) {
            //No problem this time but still it is good practice to care about exceptions.
            //Never trust user input :)
            //do something! anything to handle the exception.
        }
    }
}

十、如何分割(split)string字符串

如下所示:

String string = "004-034556";
String[] parts = string.split("-");
String part1 = parts[0]; // 004
String part2 = parts[1]; // 034556

需要注意的是,该方法的参数正则表达式,要注意对某些字符做转码。例如.在正则表达式中表示任意字符,因此,如果你要通过.号做分割,需要这样写,split("\\.")或者split(Pattern.quote("."))

如果只是为了验证字符串中是否包含某个字符,使用String的contains()方法就行。注意该方法的参数,不是正则表达式

Java编程问题top100—基础语法系列导航

Java编程问题top100—基础语法系列(一)
Java编程问题top100—基础语法系列(二)
Java编程问题top100—基础语法系列(三)
未完待续

如有错误,还请多多指教!
转载或者引用本文内容请注明来源及原作者:橘足轻重;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值