java代码的一些技巧

连续赋值

比如: a = b = true;

关于新增元素到set的一些用法:

如果新增的元素是基本类型,那么会自动判断相等。把重复的元素干掉。
如果新增的元素是复杂类型,比如数组,对象。那么判断相等的条件是该对象的内存地址。如果加入的是同一变量,那么该变量只会被加入一次。也就是说加入的时候判断相等的条件是该对象的内存地址。

public static void main(String[] args) {
    Set<int[]> set = new HashSet<>();
    int[] item = new int[]{1, 2};
    int[] item2 = item;
    set.add(item);
    set.add(item2);

    for (int[] arr : set) {
      System.out.println(arr[0] + "," + arr[1]);
    }
    // 输出:1,2

  }

特别的,如果是基本类型的封装类呢?做个试验看看!

public static void main(String[] args) {
    Set<Integer> set = new HashSet<>();
    set.add(new Integer(2));
    set.add(new Integer(2));

    for (int item : set) {
      System.out.println(item);
    }
    // 输出: 2
  }

显然,和基本类型是一样的。

复制List<T> 类型

public static void main(String[] args) {
    List<List<Integer>> container = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    list.add(3);
    list.add(4);
    container.add(list);
    // 输出 3 4
    systemContainer(container); 
    list.remove(1);
    // 输出 3 
    systemContainer(container);
  }

  public static void systemContainer(List<List<Integer>> container) {
    for (List<Integer> list : container) {
      for (int item : list) {
        System.out.print(item + " ");
      }
      System.out.println();
    }
  }

显然,如果直接把list加到container中。由于是浅复制,加入到container中的是list的内存地址。所以list改变时,container中跟着改变。那么深复制该怎么做呢?很简单:

public static void main(String[] args) {
    List<List<Integer>> container = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    list.add(3);
    list.add(4);
    container.add(new ArrayList<>(list));
    // 输出 3 4
    systemContainer(container);
    list.remove(1);
    // 输出 3 4
    systemContainer(container);
  }

在new ArrayList<>(list)的时候,可以看到源码,用到了Arrays.copy(…)。显然这是一个深复制。

如果List<Integer>中的Integer换成复杂类型呢?试验看看:

class Stu {
  String name;
  public int age;

  Stu(String name, int age) {
    this.name = name;
    this.age = age;
  }

  @Override
  public String toString() {
    return name + "--" + age;
  }
}

public class MyClass {
  public static void main(String[] args) {
    List<List<Stu>> container = new ArrayList<>();
    List<Stu> list = new ArrayList<>();
    list.add(new Stu("zhang", 3));
    list.add(new Stu("Li", 4));
    container.add(new ArrayList<>(list));
    // 输出 zhang--3 Li--4
    systemContainer(container);
    list.remove(1);
    // 输出 zhang--3 Li--4
    systemContainer(container);
    list.get(0).age = 10;
    // 输出 zhang--10 Li--4
    systemContainer(container);
  }

  public static void systemContainer(List<List<Stu>> container) {
    for (List<Stu> list : container) {
      for (Stu item : list) {
        System.out.print(item + " ");
      }
      System.out.println();
    }
  }

}

从上面的例子看出,如果List中的泛型是复杂类型的话,用 new ArrayList<>(list) 并没有深拷贝,仅仅是把list中所有对象的内存地址给到新建的ArrayList中。这也符合我们的预期。如果确实想要深拷贝,那么需要自己写拷贝函数。

复制一个数组

public static void main(String[] args) {
    String[] array2 = new String[]{"aa", "bb", "cc"};
    // 如果是简单类型数组,深拷贝。如果是复杂类型数组,浅拷贝
    String[] arr3 = Arrays.copyOf(array2, array2.length);
  }

那么如果这个数组是二维数组呢?

class Solution {
  public static void main(String[] args) {
    int[][] a = new int[3][3];
    // 这里的长度可以比原来长,也可以比原来短(截取前面的元素)
    int[][] b = Arrays.copyOf(a, a.length + 1);
    a[0][0] = 10;
    int[] a1 = {1, 2, 3};
    b[3] = a1;

    for (int i = 0; i < 4; ++i) {
      for (int j = 0; j < 3; ++j) {
        System.out.print(b[i][j] + " ");
      }
      System.out.println();
    }
    /** 输出
     * 10 0 0 
     * 0 0 0 
     * 0 0 0 
     * 1 2 3 
     */
  }
}

可以看到,如果是复杂类型数组,是浅复制。二维数组本质是一个一维数组,只不过数组类型是一个一维数组。

复制一个字符串n次返回新串

如果是java10的话,String类有一个repeat方法可以直接用。但是鉴于大部分是java8,所以可以用下面的代码。

String s = "Abc";
int n = 4;
String ret = String.join("", Collections.nCopies(n, s));

nCopies函数返回一个拥有n个s元素的列表。join表示把列表组合成一个字符串,中间的分隔符为空串,这样就曲线救国实现了复制字符串n次。

创建一个元素类型是List的数组

List<Integer>[] tower = new ArrayList[3];

上面的创建方法会报一个安全警告,不用管它。

保留两位小数

class Solution {
  public static void main(String[] args) {
    double d = 2.344;
    // 保留两位小数,多余位直接舍去
    System.out.println(((int)(d * 100)) / 100.0);
    // 保留两位小数,四舍五入
    System.out.println(((int)(d * 100 + 0.5)) / 100.0);
  }
}

Arrays.sort自定义排序

import java.util.*;

public class Main {
    public static void main(String[] args){
      	//不能使用基本数据类型
        Integer[] arr = {5,4,7,9,2,12,54,21,1};
        //降序
        Arrays.sort(arr, (a, b) -> {
            //返回值>0交换
            return b-a;
        });
        System.out.println(Arrays.toString(arr));
    }
}

List和Array互相转换

public static void main(String[] args) {
    List<String> testList = new ArrayList<String>(){{add("aa");add("bb");add("cc");}};
    String[] array2 = testList.toArray(new String[0]);
    // 直接用Arrays.asList转成的List不能增删元素。两者具体区别可百度
    List<String> list = new ArrayList<>(Arrays.asList(array2));
	
	// 还可以这么转
	List<int[]> ret = new ArrayList<>();
	int[][] tp = ret.toArray(new int[0][0]);
  }

定义常量

final double PI = 3.14; // PI是一个常量
double r = 5.0;
double area = PI * r * r;
PI = 300; // compile error!

多行字符串

如果我们要表示多行字符串,使用+号连接会非常不方便:

String s = "first line \n"
         + "second line \n"
         + "end";

从Java 13开始,字符串可以用"""…"""表示多行字符串(Text Blocks)了。举个例子:

public class Main {
    public static void main(String[] args) {
        String s = """
                   SELECT * FROM
                     users
                   WHERE id > 100
                   ORDER BY name DESC
                   """;
        System.out.println(s);
    }
}

上述多行字符串实际上是5行,在最后一个DESC后面还有一个\n。如果我们不想在字符串末尾加一个\n,就需要这么写:

String s = “”"
SELECT * FROM
users
WHERE id > 100
ORDER BY name DESC""";
还需要注意到,多行字符串前面共同的空格会被去掉,即:

String s = “”"
…SELECT * FROM
… users
…WHERE id > 100
…ORDER BY name DESC
…""";
用.标注的空格都会被去掉。

如果多行字符串的排版不规则,那么,去掉的空格就会变成这样:

String s = “”"
… SELECT * FROM
… users
…WHERE id > 100
… ORDER BY name DESC
… “”";
即总是以最短的行首空格为基准。

输入输出

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建Scanner对象
        System.out.print("Input your name: "); // 打印提示
        String name = scanner.nextLine(); // 读取一行输入并获取字符串
        System.out.print("Input your age: "); // 打印提示
        int age = scanner.nextInt(); // 读取一行输入并获取整数
        System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出
    }
}

switch case的用法

public class Main {
    public static void main(String[] args) {
        String fruit = "apple";
        switch (fruit) {
        case "apple":
            System.out.println("Selected apple");
            break;
        case "pear":
            System.out.println("Selected pear");
            break;
        case "mango":
            System.out.println("Selected mango");
            break;
        default:
            System.out.println("No fruit selected");
            break;
        }
    }
}

注意:不要忘记break,不要忘记default.

java12 升级版switch

使用switch时,如果遗漏了break,就会造成严重的逻辑错误,而且不易在源代码中发现错误。从Java 12开始,switch语句升级为更简洁的表达式语法,使用类似模式匹配(Pattern Matching)的方法,保证只有一种路径会被执行,并且不需要break语句:

public class Main {
    public static void main(String[] args) {
        String fruit = "apple";
        switch (fruit) {
        case "apple" -> System.out.println("Selected apple");
        case "pear" -> System.out.println("Selected pear");
        case "mango" -> {
            System.out.println("Selected mango");
            System.out.println("Good choice!");
        }
        default -> System.out.println("No fruit selected");
        }
    }
}

注意新语法使用->,如果有多条语句,需要用{}括起来。不要写break语句,因为新语法只会执行匹配的语句,没有穿透效应。

很多时候,我们还可能用switch语句给某个变量赋值。例如:

int opt;
switch (fruit) {
case "apple":
    opt = 1;
    break;
case "pear":
case "mango":
    opt = 2;
    break;
default:
    opt = 0;
    break;
}

使用新的switch语法,不但不需要break,还可以直接返回值。把上面的代码改写如下:

public class Main {
    public static void main(String[] args) {
        String fruit = "apple";
        int opt = switch (fruit) {
            case "apple" -> 1;
            case "pear", "mango" -> 2;
            default -> 0;
        }; // 注意赋值语句要以;结束
        System.out.println("opt = " + opt);
    }
}

yield

大多数时候,在switch表达式内部,我们会返回简单的值。

但是,如果需要复杂的语句,我们也可以写很多语句,放到{…}里,然后,用yield返回一个值作为switch语句的返回值:

public class Main {
    public static void main(String[] args) {
        String fruit = "orange";
        int opt = switch (fruit) {
            case "apple" -> 1;
            case "pear", "mango" -> 2;
            default -> {
                int code = fruit.hashCode();
                yield code; // switch语句返回值
            }
        };
        // opt = -1008851410
        System.out.println("opt = " + opt);
    }
}

从Java 14开始,switch语句正式升级为表达式,不再需要break,并且允许使用yield返回值。

字符串和数据类型互转

字符串转int
Integer.parseInt(str)
int 转字符串
Integer.toString(number)

StringBuffer和StringBuilder类

上述两种字符串可以被修改,不产生新的字符串。StringBuilder不是线程安全的。速度快。StringBuffer线程安全,速度慢。

StringBuffer常用方法:

StringBuffer sb = new StringBuffer(“abcd”)
sb.append(“aaa”)
sb.reverse()
sb.delete(2, 3) // delete(int start, int end) 左闭右开
deleteCharAt(int index)
sb.insert(4, “java”)
sb.replace(2, 4, “java”) // end字符不会被替换
sb.toString()

StringBuilder 同理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值