Java编程问题top100---基础语法系列(二)
感觉github上的翻译质量并没有想象中的那么好,感谢前辈的努力,但是还是得自力更生一步一步看国外文章自己动手翻译整合,码字不易,点赞支持~
萌新须知:平时写代码要老老实实判空,毕竟平时都是共同开发,不是你一个人单干,万一哪天对方改代码了,你调人家方法,返回个null给你,你也得背锅,另外不建议用assert断言,生产环境会关掉assert的。
六、如何测试一个数组是否包含指定的值?
指定数组,如:
public static final String[] VALUES = new String[]{"id", "name", "location"};
有哪些比较好的方式,判断这个数组 VALUES 是否包含值id?
简单且优雅的方法:
-
Arrays.asList(…).contains(…)
-
使用 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)应当是一样的
如何更快地重写这两个方法呢?
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);
}
}
- 代码编辑区右键,然后
(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—基础语法系列(三)
未完待续
如有错误,还请多多指教!
转载或者引用本文内容请注明来源及原作者:橘足轻重;