Java-usage

重写排序规则

一维数组降序

1
2
3
4
5
6
7
8
9
10
Integer[] arr = {1,3,2};
Arrays.sort(arr, new Comparator<Integer>() { // 使用泛型,整型数组需要是Integer封装类
public int compare (Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int i = 0; i < arr.length; ++i) {
System.out.print(arr[i]);
System.out.print(" ");
}
1
2
3
4
5
6
Integer[] arr = {1,3,2};
Arrays.sort(arr, (o1, o2) -> {return o2 - o1;}); // 使用lambda表达式
for (int i = 0; i < arr.length; ++i) {
System.out.print(arr[i]);
System.out.print(" ");
}

二维数组按指定列排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
int[][] nums = {{1,3,2}, {2,1,3}, {3,2,1}};
Arrays.sort(nums, new Comparator<int[]>() {
public int compare(int[] arr1, int[] arr2) {
return arr1[1] - arr2[1]; // 指定第二列排序
}
});
// System.out.println(nums);

int[] order = {1, 0, 2}; // 先按第1列排,再按第0列排,最后再按第2列排;
int[][] nums = {{2,3,1}, {1,3,2}, {2,1,3}, {2,2,3}, {2,1,2}};
Arrays.sort(nums, new Comparator<int[]>() {
public int compare(int[] arr1, int[] arr2) {
for (int i = 0; i < order.length; ++i) {
int k = order[i];
// 经过测试如果没有这句话,只按order[0]排
if (arr1[k] == arr2[k]) continue; // 关键!!
return arr1[k] - arr2[k]; // 升序
}
return 0;
}
});

int[] order = {1, 0}; // 先按第1列降序排,再按第0列升序排
int[][] nums = {{2,3,1}, {1,3,2}, {2,1,3}, {2,2,3}, {2,1,2}};
Arrays.sort(nums, new Comparator<int[]>() {
public int compare(int[] arr1, int[] arr2) {
for (int i = 0; i < order.length; ++i) {
int k = order[i];
if (arr1[k] == arr2[k]) continue; // 关键!!
if (k == 1) {
return arr2[k] - arr1[k];
} else {
return arr1[k] - arr2[k];
}
}
return 0;
}
});
// 输出测试
for (int i = 0; i < nums.length; ++i) {
for (int j = 0; j < nums[0].length; ++j) {
System.out.print(nums[i][j]);
System.out.print(" ");
}
System.out.println();
}

字符串的排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String s = "cab";
char[] ch = s.toCharArray(); // 通过转成char[]修改排序规则
Arrays.sort(ch);
s = String.valueOf(ch); // 升序

Character[] Ch = new Character[ch.length]; // 如果要降序,需要构建Character封装
for (int i = 0; i < ch.length; ++i) Ch[i] = ch[i];
Arrays.sort(Ch, new Comparator<Character>() {
public int compare(Character c1, Character c2) {
return c2 - c1;
}
});
for (int i = 0; i < ch.length; ++i) ch[i] = Ch[i];
s = String.valueOf(Ch);
System.out.println(s);

自动装箱&拆箱

  • 什么是自动装箱&拆箱?

Java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,这就是装箱和拆箱,

  • 什么时候会进行装箱&拆箱?
    • 进行 = 赋值操作(装箱或拆箱)
    • 进行+,-,*,/混合运算 (拆箱)
    • 进行>,<,==比较运算(拆箱)
    • 调用equals进行比较(装箱)
    • ArrayList,HashMap等集合类 添加基础类型数据时(装箱)
  • 一道面试题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void testAutoBox2() {
//1
int a = 100;
Integer b = 100;
System.out.println(a == b); // true

//2
Integer c = 100;
Integer d = 100;
System.out.println(c == d); // true

//3
c = 200;
d = 200;
System.out.println(c == d); // false
}

解释:

对于case1,就是正常的自动装箱;

对于case2 和case3,涉及到两个知识点:

  1. Integer声明的是一个对象,用==来比较两个对象其实是比较二者所指向的地址值是否相等;
  2. 创建Integer对象时并不是简单new一个,还会涉及到用IntegerCache做一个cache,而这个cache是可以设置的。

一般缓存设置为-128 ~127范围内,如果初始化在这个区间,那么两个变量指向的会是同一个地址,否则要指向两块不同的存储区间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];

static {
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;

cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
....

Reference

5分钟彻底理解-Java自动装箱、拆箱w

异常机制代码执行顺序

在本周实习coding的时候遇到这样一个问题,如果code2处发生异常,整个程序是直接终止吗?

1
2
3
4
5
6
7
8
try {
code1
code2 // 发生异常
code3
} catch {
code4
}
code5

借此机会,对异常的代码执行顺序进行一个简单的整理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {

public static void main(String[] args) throws Exception {
try {
throw new Exception("发生异常!"); // code1
// System.out.println("code1"); IDE会提示为无效代码,会产生编译错误。
} catch (Exception e) {
e.printStackTrace(); // 捕获到了code1的代码
} finally {
System.out.println("finally"); // try完无论抛不抛异常都会执行的代码
}
System.out.println("end"); // 被catch到的异常会执行,没被catch到的或者catch完有抛了新的异常都不会执行。

if(true) {
throw new Exception("参数越界"); // IDE提示在函数头抛出异常
}
System.out.println("异常后"); //抛出异常,不会执行
}
}

/*
java.lang.Exception: 发生异常!
at Test.main(Test.java:7)
Exception in thread "main" java.lang.Exception: 参数越界
at Test.main(Test.java:17)
finally
end

Process finished with exit code 1
*/

参考

1、https://blog.csdn.net/qq_2300688967/article/details/79425729

List-int-Integer之间的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// int[] 转 List<Integer>
List<Integer> list1 = Arrays.stream(data).boxed().collect(Collectors.toList());
// Arrays.stream(arr) 可以替换成IntStream.of(arr)。
// 1.使用Arrays.stream将int[]转换成IntStream。
// 2.使用IntStream中的boxed()装箱。将IntStream转换成Stream<Integer>。
// 3.使用Stream的collect(),将Stream<T>转换成List<T>,因此正是List<Integer>。

// int[] 转 Integer[]
Integer[] integers1 = Arrays.stream(data).boxed().toArray(Integer[]::new);
// 前两步同上,此时是Stream<Integer>。
// 然后使用Stream的toArray,传入IntFunction<A[]> generator。
// 这样就可以返回Integer数组。
// 不然默认是Object[]。

// List<Integer> 转 Integer[]
Integer[] integers2 = list1.toArray(new Integer[0]);
// 调用toArray。传入参数T[] a。这种用法是目前推荐的。
// List<String>转String[]也同理。

// List<Integer> 转 int[]
int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();
// 想要转换成int[]类型,就得先转成IntStream。
// 这里就通过mapToInt()把Stream<Integer>调用Integer::valueOf来转成IntStream
// 而IntStream中默认toArray()转成int[]。

// Integer[] 转 int[]
int[] arr2 = Arrays.stream(integers1).mapToInt(Integer::valueOf).toArray();
// 思路同上。先将Integer[]转成Stream<Integer>,再转成IntStream。

// Integer[] 转 List<Integer>
List<Integer> list2 = Arrays.asList(integers1);
// 最简单的方式。String[]转List<String>也同理。

// 同理
String[] strings1 = {"a", "b", "c"};
// String[] 转 List<String>
List<String> list3 = Arrays.asList(strings1);
// List<String> 转 String[]
String[] strings2 = list3.toArray(new String[0]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int[] nums = new int[10000];
for (int i = 0; i < nums.length; ++i) {
nums[i] = i;
}

long start = System.currentTimeMillis();

Integer[] arr1 = new Integer[10000];
for (int i = 0; i < 10000; ++i) {
arr1[i] = nums[i];
}

long end = System.currentTimeMillis();
System.out.println(end - start); // 1


start = System.currentTimeMillis();

Integer[] arr2 = Arrays.stream(nums).boxed().toArray(Integer[]::new);

end = System.currentTimeMillis();
System.out.println(end - start); // 62

还是用for自己转吧。。