TENCHIANG / blog

issue blog
10 stars 1 forks source link

Java笔记——Part3(常用API_1) #47

Open TENCHIANG opened 5 years ago

TENCHIANG commented 5 years ago

java.util.Scanner:输入

  1. 可以自动关闭sc.close()
  2. 默认空白字符是间隔符
  3. 如果指定类型,如果输入其他类型,那么终止(除了空白符)
    import java.util.Scanner;
    public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextInt()) System.out.println(sc.nextInt()); // hasNextInt会引起block
    }
    }

    使用sc.hasNext:避免java.util.InputMismatchException 注意:一般输入字符串不会mismatch的,会一直next,除非输入EOFCtrl+D,如果对EOF进行next接受那么会java.util.NoSuchElementException 输入字符串hasNext一直为true,输入EOF那么返回false Scanner的一个小例子:

    
    import java.util.Arrays;
    import java.util.Scanner;

public class Main {

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    System.out.print("先输入数组的长度: ");
    int[] arr = new int[sc.hasNextInt() ? sc.nextInt() : 0];
    if (arr.length == 0) return;

    int max = 0;
    for (int i = 0; i < arr.length; i++) {
        System.out.print("请输入第" + (i + 1) + "个变量: ");
        if (sc.hasNextInt()) arr[i] = sc.nextInt();
        if (arr[max] < arr[i]) max = i;
    }
    System.out.println(Arrays.toString(arr) + "最大值为" + arr[max]);
}

}

可以看到,数组可以在运行时定义(变量),但是一旦定义好,那么久无法改变了

## 判断偶数的三种方法
```Java
public class Main {

    public static void main(String[] args) {
        int odd = 7, even = 8;
        System.out.println(isEven1(odd) + ", " + isEven1(even));
        System.out.println(isEven2(odd) + ", " + isEven2(even));
        System.out.println(isEven3(odd) + ", " + isEven3(even));
    }

    /**
     * 被2整除(为0)就是偶数 为1的是奇数
     * 0 % 2 = 0
     * 1 % 2 = 1
     * 2 % 2 = 0
     * 3 % 2 = 1
     */
    static boolean isEven1 (int num) {
        return num % 2 == 0;
    }

    /**
     * 与自身小一的数相与 偶数为0 奇数自身小一的数
     * 7 & 6 = 0x00000007 & 0x00000006 = 0111 & 0110 = 0110 = 6
     * 8 & 7 = 0x00000008 & 0x00000007 = 1000 & 0111 = 0
     */
    static boolean isEven2 (int num) {
        return (num & num - 1) == 0;
    }

    /**
     * 按位与自身的负数形式等于自身的为偶数 奇数为1
     * 负数的16进制是取反加一
     * 8 & -8 = 0x00000008 & 0xfffffff8 = 8
     * 7 & -7 = 0x00000007 & 0xFFFFFFF9 = 1
     */
    static boolean isEven3 (int num) {
        return (num & -num) == num;
    }
}

java.util.Random:随机数

nextInt默认为整个int范围,传入bound则是[0, bound),意思是 0 <= x < bound 小技巧:整体+1就是[1, bound]( 1 <= x <= bound),或者(0, bound](0 < x <= bound)

import java.util.Random;

public class Main {

    public static void main(String[] args) {
        Random r = new Random();

        int bound = 3;
        int res = r.nextInt(bound);
        System.out.println(res); // [0, bound)
        System.out.println(res + 1); // [1, bound]
    }
}

注意:

综合应用:猜数字游戏(其实超纲了,主要已经是异常处理了)

import java.util.Random;
import java.util.Scanner;
import java.util.InputMismatchException; // 格式输入错误
import java.util.NoSuchElementException; // EOF

public class Main {

    public static void main(String[] args) {

        int bound;
        Scanner sc = null;
        while (true) {
            try {
                System.out.print("请输入猜数范围(1到几):");
                sc = new Scanner(System.in);
                if ((bound = sc.nextInt()) <= 1) continue;

                break;
            } catch (InputMismatchException e) { // 输入格式错误 还能重试
                System.out.print("请输入数字!");
            } catch (IllegalStateException e) { // 这个错误是属于 java.lang 的
                System.out.println("标准输入已关闭");
                return; // 没救了 因为一旦 System.in关闭 就开启不了了
            } catch (NoSuchElementException e) {
                System.out.println("你输入了EOF");
                return; // 似乎也没救了
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
        }
        int res = new Random().nextInt(bound) + 1; // [1, bound]

        int num;
        int count = 0;
        while (true) {
            try {
                System.out.print("请在1到" + bound + "之间猜一个数字:" + res);
                sc = new Scanner(System.in);
                if ((num = sc.nextInt()) < 1) continue;

                count++;
                if (num < res) System.out.println("小了");
                else if (num > res) System.out.println("大了");
                else break;
            } catch (InputMismatchException e) { // 输入格式错误 还能重试
                System.out.print("请输入数字!");
            } catch (IllegalStateException e) { // 这个错误是属于 java.lang 的
                System.out.println("标准输入已关闭");
                return; // 没救了 因为一旦 System.in关闭 就开启不了了
            } catch (NoSuchElementException e) {
                System.out.println("你输入了EOF");
                return; // 似乎也没救了
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
        }
        System.out.println("猜对了!一共猜了" + count + "次");
    }
}

参考: ScannerInt循环读取判断整数(用异常) 在同一进程中多次调用scanner出现NoSuchElementException异常解决办法 为什么scanner 抛出异常后就一直在这循环啊 How to avoid Scanner from eof and keep him alive System.in关闭问题 java中的 try、catch、finally及finally执行顺序详解 关闭扫描仪而不关闭System.in

使用try-with-resources(>=jdk7)重构猜数字游戏

import java.util.Random;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        try (Scanner sc = new Scanner(System.in)) {
            int bound = 0;
            while (true) {
                System.out.print("请输入猜数范围(1到几):");
                try {
                    bound = Integer.parseInt(sc.next());
                } catch (NumberFormatException e) {
                    System.out.print("请输入数字!");
                    continue;
                }
                if (bound > 1) break;
            }

            int count = 0;
            int res = new Random().nextInt(bound) + 1; // [1, bound]
            while (true) {
                System.out.print("请在1到" + bound + "之间猜一个数字:" + res);
                int num = 0;
                try {
                    num = Integer.parseInt(sc.next());
                } catch (NumberFormatException e) {
                    System.out.print("请输入数字!");
                    continue;
                }
                if (num < 1) continue;

                count++;
                if (num < res) System.out.println("小了");
                else if (num > res) System.out.println("大了");
                else break;
            }
            System.out.println("猜对了!一共猜了" + count + "次");
        }
    }
}

java.util.ArrayList

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        if (list.add("a") == false) {
            System.out.println("插入数据失败");
            return;
        }
        list.add("z");
        list.add("b");
        list.add("c");

        list.get(1);
        String removed = list.remove(1);
        System.out.println("已删除" + removed);

        System.out.println(list);
        System.out.println("长度为" + list.size());

        list.forEach(str -> System.out.print(str + " "));
    }
}

ArrayList包装类示范(除了泛型填包装类,其它都当做基本类型用就得了>=jdk5的自动装箱自动拆箱>)

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();

        list.add(100);
        list.add(200);
        list.add(300);

        int num = list.get(2);

        System.out.println(list + " " + num);
    }
}

java.lang.包装类

重点要记的就两个,Integer和Character,其它都是首字母大写

自动装箱自动拆箱(>=jdk5)

java.lang.String

创建字符串 3+1 种方法

3种构造方法+1种直接创建 注意:双引号括起来的,就是字符串对象(类似于自动装箱但不是),且双引号括起来的字符串(直接创建的字符串)都在字符串常量池中(其他方式生成的字符串不在)

public class Main {

    public static void main(String[] args) {
        String s1 = new String();
        String s2 = new String(new char[]{ '0', 'A', 'a' });
        String s3 = new String(new byte[]{ 48, 65, 97 });
        String s4 = "0Aa";

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
    }
}

字符串常量池

直接用双引号创建的字符串,是在字符串常量池的,其他形式创建的字符串不在(虽然也是常量) 字符串常量池是堆里面的一块区域(>=jdk7),这块区域专门保存堆中字符串的地址(字节数组) 注意比较运算符==

字符串常用方法

public class Main {

public static void main(String[] args) {
    String s1 = "0Aa";
    System.out.println(s1.charAt(1)); // A
    System.out.println(s1.codePointAt(1)); // 65
    System.out.println(s1.indexOf('A')); // 1
    System.out.println(s1.indexOf("A")); // 1
    System.out.println(s1.substring(1)); // Aa [beginIndex, length())
    System.out.println(s1.substring(1, 2)); // A [beginIndex, endIndex)

    System.out.println(Arrays.toString(s1.toCharArray())); // [0, A, a]
    System.out.println(Arrays.toString(s1.getBytes())); // [48, 65, 97]

    System.out.println("09990".replace('0', '1')); // 19991
    System.out.println("aabbccaa".replace("aa", "zz")); // zzbbcczz

    System.out.println("abc" == "abc".toLowerCase()); // true
    System.out.println("abc" == "abc".toUpperCase()); // false

    System.out.println(Arrays.toString("aaa,bbb,ccc".split(",")));
}

}

注意:
* replace传字符串其实是字符串序列,`"aaa".replace("aa", "b")`等于多少?`ba`还是`ab`
如果是字符串序列,那么是`ba`,意思就是从字符串**字面值从左到右**开始尽量多的匹配(贪心原则)
* split的参数字符串是正则表达式,所以不能直接切英文句点`.`,需要用`\\.`

## static关键字
* 相同点、共性、不改变的
* static的变量或方法是属于类的,而不是属于对象(但是可以共享使用)
* 静态方法只能访问静态变量和静态方法,普通的既可以访问静态也可以访问普通
* 静态变量和方法都在方法区(就是存类相关信息的区域)
* 静态代码块:第一次用到类时,静态代码块执行且执行一次(而且比所有非静态要先)(适合一次性的对静态变量赋值)
* 可以根据静态变量实现类似id的自动生成

## java.util.Arrays 数组工具类
* `public static String toString(数组)`数组转为字符串[x, x, x]格式
* `public static void sort(数组)`数组升序排序(从小到大)
```java
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        int[] arr = {4, 3, 2, 1};

        Arrays.sort(arr);
        String str = Arrays.toString(arr);
        System.out.println(str); // [1, 2, 3, 4]

        char[] chars = str.toCharArray();
        Arrays.sort(chars);
        System.out.println(chars); // char[]可以直接打印    ,,,1234[]
    }
}

java.lang.Math数学工具类