一、String

1. String 封装字符串数据

1)直接给对象赋值字符串,例:

String name = "蔡徐坤"

2)利用 String 类的构造器

public String( )                           ----     创建一个空白字符串对象,不含有任何内容

public String(String original)      ----     根据传入的字符串内容,来创建字符串对象

public String(char[] chars)         ----     根据字符数组的内容,来创建字符串对象

public String(byte[] bytes)         ----      根据字节数组的内容(ASCII转换),来创建字符串对象

2. String 的常用方法

public class Test {
    public static void main(String[] args) {
        String s1 = "abcdefg";
        // 1.获取字符串的长度
        System.out.println(s1.length());
        // 2.提取对应索引位置的字符(0开始)
        System.out.println(s1.charAt(2));
        // 字符串的遍历
        for (int i = 0; i < s1.length(); i++)
        {
            char ch = s1.charAt(i);
            System.out.println(ch);
        }
        // 3.把字符串的所有字符提取到一个char数组中
        char[] chars = s1.toCharArray();
        for (int i = 0; i < s1.length(); i++)
        {
            System.out.println(chars[i]);
        }
        // 4.比较字符串内容
        String s2 = new String("abcdefg");
        System.out.println(s1 == s2);      // false,因为字符串直接比较地址
        System.out.println(s1.equals(s2)); // true
        // 5.忽略大小写比较字符串内容(常用于验证码比较)
        String s3 = "ABCDEFG";
        System.out.println(s1.equalsIgnoreCase(s3));
        // 6.截取字符串的部分内容
        String c1 = s1.substring(2);
        String c2 = s1.substring(1,4);
        System.out.println(c1);
        System.out.println(c2);
        // 7.替换字符串的部分内容
        String s4 = "fzc是一个臭傻逼";
        System.out.println(s4.replace("臭傻逼", "***"));
        // 8.判断字符串是否包含某个内容
        System.out.println(s1.contains("abc")); // true
        System.out.println(s1.contains("ABC")); // false,精准判断
        // 9.判断字符串是否以某内容开头
        System.out.println(s1.startsWith("abc")); // true
        // 10.把字符串以指定内容分割(返回字符串数组)
        String c3 = "A,B,C,D";
        String[] letters = c3.split(",");
        for (int i = 0; i < letters.length; i++)
        {
            System.out.println(letters[i]);
        }
    }
}

3. String 的注意事项

1)String 创建的字符串对象不可变(不可直接赋值修改)

补充:"+"连接改变的,实质上是产生了一个新字符串,通过改变变量的地址来指向新字符串对象

2)以"..."方式写出的字符串对象,会在堆内存中的字符串常量池中存储,而且相同内容的字符串只存储一份

3)以 new 方式创建字符串对象,每一次都是在堆内存开辟新空间存储

4)字符串内容比较时尽量使用 equals("=="可能会出bug)

4. String 的案例(面试题)

1)请问下面的代码需要开辟几个 String 大小的空间

String s1 = new String("abc");

答:1个或2个。如果字面量"abc"没有存储到字符串常量池中,会先将"abc"存储到常量池后,再在堆内存中开辟新空间来存储变量所指向的字符串对象。

2)在上一问的代码基础上,请问下面的代码需要开辟几个 String 大小的空间

String s2 = "abc";

答:0个。在上一问的代码基础上,常量池中已经存储了"abc",所以不需要开辟新空间

3)判断打印结果

public class Test {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "ab";
        String s3 = s2 + "c";
        System. out.println(s1 == s3);
    }
}

答:false,在堆中调用常量池中的"ab"创建了一个新的"abc"对象

4)判断打印结果

public class Test {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "a" + "b" + "c";
        System. out.println(s1 == s2);
    }
}

答:true,Java程序存在编译优化机制,"a" + "b" + "c"自动优化为"abc"

二、ArrayList(集合)

1.集合

一种数据容器,类似于数组,ArrayList 是其中的一种

public class Test {
    public static void main(String[] args) {
        // 1.创建一个ArrayList对象
        ArrayList list1 = new ArrayList();
        // 2.在集合末尾添加数据
        list1.add(666);
        list1.add(666);
        list1.add(98.5);
        list1.add("cxk");
        // 3.创建一个约束类型的ArrayList对象
        ArrayList<String> list2 = new ArrayList<>();
        //list2.add(98.5);  // 类型不符会报错
        list2.add("cxk");
        // 4.在指定索引位置上添加元素
        list1.add(1,123);
        // 5.获取指定索引位置的元素
        System.out.println(list1.get(1));
        // 6.获取集合全部元素的个数
        System.out.println(list1.size());
        // 7.删除指定索引位置的元素,并返回被删除的元素
        System.out.println(list1.remove(1));
        // 8.删除指定内容的元素,成功返回true,反之返回false
        // 补充:如果集合内有重复元素,只删除第一个元素
        System.out.println(list1.remove("cxk"));
        // 9.修改指定索引位置的元素,返回修改前的元素
        System.out.println(list1.set(1,"abc"));
        System.out.println(list1);
    }
}

三、Object 类

在 java.lang 包下,是所有 class 的超类 -- 所有类都是 Object 类的子孙类

1. toString 方法

返回对象的字符串表示形式,常用于重写后返回对象的内容

@Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
public class Test{
    public static void main(String[] args) {
        Student s = new Student("cxk");
        System.out.println(s);
    }
}

2. equals 方法

默认是比较两个对象的地址是否相等,可以重写后比较对象的内容,返回比较的结果(boolean)

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }

3. clone 方法

当某个对象调用这个方法时,会复制一个一样的对象返回

public class Student implements Cloneable{    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test{
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s1 = new Student("cxk");
        Student s2 = (Student) s1.clone();
        System.out.println(s1.equals(s2));
    }
}

注意:1)clone 方法是 protected 范围下,所以需要在类中重写才能使用 

           2)Cloneable 接口中没有成员,是一个标记接口,使JVM能够识别此类可以用 clone 方法

           3)throws CloneNotSupportedException 是为了抛出异常,编译器会认为 clone 方法直接调用可能不安全

           4)clone 所拷贝的对象为浅拷贝

补充:浅拷贝和深拷贝

四、Objects 类

Objects 类不同于 Object 类,在 java.util 包下,是一个工具类(不能被继承),提供一些静态方法

1. equals 方法

先做地址判断,再非空判断,最后比较内容

2. isNull、nonNull 方法

判断该对象是否为 null

五、包装类

1.认识包装类

将基本数据类型的数据包装为对象,实现万物皆对象

java开发用ide还是android studio_开发语言

2.包装类的使用

1)自动装箱:将基本数据类型自动转换为包装类型

Integer a = 12;

2)自动拆箱:将包装类型自动转换为基本数据类型

int b = a;

3)泛型:不支持基本数据类型,但支持包装类型

//ArrayList<int> list = new ArrayList<>();
        ArrayList<Integer> list = new ArrayList<>();
        int a = 10;
        list.add(a);
        int b = list.get(0);

3.包装类的常见操作

1)把基本数据类型转换为字符串类型(两种方法)

Integer a = 12;
        String s1 = Integer.toString(a);
        System.out.println(s1+3);//"123"

        String s2 = a.toString();
        System.out.println(s2+3);//"123"

2)把字符串类型转换成对应的基本数据类型(两种方法)

注意:字符串类型的数值一定要是正确的数据类型,否则会出错

String s1 = "12";
        int a1 = Integer.parseInt(s1);
        System.out.println(a1+3);// 15
        int b1 = Integer.valueOf(s1);
        System.out.println(b1+3);// 15

        String s2 = "99.5";
        double a2 = Double.parseDouble(s2);
        System.out.println(a2+0.5);// 100.0
        double b2 = Double.valueOf(s2);
        System.out.println(b2+0.5);// 100.0

建议使用 valueOf 方法,这样便于维护和修改

六、StringBuilder、StringBuffer 和 StringJoiner

1. StringBulider

代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,用来操作字符串

好处:StringBuilder 比 String 更适合做字符串的修改操作,效率会更高,代码也会更简洁。

1)调用构造器

StringBuilder s1 = new StringBuilder();
StringBuilder s2 = new StringBuilder("abc");

无参构造器创建的对象是一个不包含任何字符,默认16个字符大小的容器

而有参构造器创建的对象是指定字符串内容,或指定字符串大小的容器

2)append 方法

append 方法可以接收任意数据类型,如 int,double,String,boolean,数组等

StringBuilder s1 = new StringBuilder();
        s1.append(111);
        s1.append("acb");
        s1.append(99.2);
        // 支持链式编程
        s1.append(true).append(666);

注意:append 方法执行后会返回该对象,所以可以支持链式编程,递归思想等

3)reverse 和 length 方法

reverse:字符串反转

length:返回字符串长度

s1.reverse();
        int len = s1.length();

4)toString 方法

将 StringBuilder 类型转换为 String 类型

String rs = s1.toString();

2. StringBuffer

用法:和上面的 StringBuilder 基本一致

作用:StringBuilder 是线程不安全的,而 StringBuffer 是线程安全的

3. StringJoiner

JDK8 开始才有的,跟 StringBuilder 一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。

好处:不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁

public class Test{
    public static void main(String[] args) {
        StringJoiner s = new StringJoiner(",");
        s.add("1").add("2").add("3");
        System.out.println(s);
    }
}

最后结果为:1,2,3,它在创建对象时定义了一个分隔符,每次 add 操作后都会添加分隔符(最后一次不会)

public class Test{
    public static void main(String[] args) {
        StringJoiner s = new StringJoiner(",","[","]");
        s.add("1").add("2").add("3");
        System.out.println(s);
    }
}

最后结果为:[1,2,3],定义分隔符的同时也可以添加开始符和结束符,创建对象后即存在

注意:StringJoiner 的 add 操作只能传输字符串类型

七、Math、System、Runtime、BigDecimal

1. Math

代表数学,是一个工具类,里面提供的都是对数据进行操作的一些静态方法。

java开发用ide还是android studio_bc_02

public class Test{
    public static void main(String[] args) {
        System.out.println(Math.abs(-12));  // 12
        System.out.println(Math.abs(-3.14));// 3.14

        System.out.println(Math.ceil(3.00001));// 4.0
        System.out.println(Math.floor(2.9999));// 2.0

        System.out.println(Math.round(3.4999));// 3
        System.out.println(Math.round(3.5000));// 4

        System.out.println(Math.max(1,2));    // 2
        System.out.println(Math.max(1.2,1.3));// 1.3

        System.out.println(Math.pow(2,3));    // 2的3次方 8.0
        System.out.println(Math.pow(1.2,1.1));// 1.2的1.1次方 1.222079251376429

        System.out.println(Math.random()); // 范围:[0.0,1.0)
    }
}

2. System

代表程序所在的系统,也是一个工具类。

java开发用ide还是android studio_java_03

1)exit 方法(一般不要使用)

public class Test{
    public static void main(String[] args) {
        System.out.println(1);
        System.exit(0); // 正常结束进程以0为退出参数
        System.out.println(2);
    }
}

结果:只打印了1,因为 exit 手动结束了程序,不会在往后运行

注意:非0的状态代码表示异常终止,0为正常终止

2)currentTimeMillis 方法

返回从1970-01-01 00:00:00 开始计算,到当前时间的毫秒(ms)值

常用于计算程序运行时间

public class Test{
    public static void main(String[] args) {
        long time1 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            System.out.println("当前数字为:"+i);
        }
        long time2 = System.currentTimeMillis();
        System.out.println((time2-time1)/1000.0+"s");
    }
}

java开发用ide还是android studio_java_04

3. Runtime

Runtime是一个单例类,代表程序所在的运行环境。

java开发用ide还是android studio_字符串_05

public class Test{
    public static void main(String[] args) throws IOException, InterruptedException {
        Runtime r = Runtime.getRuntime();
        // 我强大的电脑是20核处理器
        System.out.println(r.availableProcessors());
        // 1024 Byte = 1 KB    1024 KB = 1 MB
        System.out.println(r.totalMemory()/1024.0/1024.0+"MB");
        System.out.println(r.freeMemory()/1024.0/1024.0+"MB");
        // QQ , 启动
        Process p = r.exec("E:\\腾讯QQ\\Bin\\QQScLauncher.exe");
        Thread.sleep(5000); // 使程序暂停5秒
        p.destroy(); // 销毁接收的对象
        // 退出程序
        r.exit(0);
    }
}

注意:1)Runtime 是单例类,只能通过 getRuntime 来获取 Runtime 唯一的对象

           2)调用 exec 来运行外部程序时,会出现安全警告,需要 throws IOException 来抛出异常

           3)sleep 方法以后会学,这里不再说明

4. BigDecimal

属于math包下,用于解决浮点型运算时,出现结果失真的问题。

public class Test{
    public static void main(String[] args) throws IOException, InterruptedException {
        double a = 0.1;
        double b = 0.2;
        System.out.println(a+b); // 0.30000000000000004
    }
}

如上面代码所示,在某些情况下,Java中的浮点型运算会出现失真问题,所以要使用BigDecimal 

java开发用ide还是android studio_字符串_06

public class Test{
    public static void main(String[] args) throws IOException, InterruptedException {
        double a = 0.1;
        double b = 0.3;

        BigDecimal a1 = new BigDecimal(Double.toString(a));
        BigDecimal b1 = BigDecimal.valueOf(b); // 推荐使用这种方式

        System.out.println(a1.add(b1));     // 加法
        System.out.println(a1.subtract(b1));// 减法
        System.out.println(a1.multiply(b1));// 乘法

        BigDecimal c = a1.divide(b1,2, RoundingMode.HALF_UP);// 除法
        double c1 = c.doubleValue();
        System.out.println(c1);
    }
}

注意:如果运算结果本身不为固定精度,则在运算时要设置结果的精度和取舍模式

BigDecimal c = a1.divide(b1,2, RoundingMode.HALF_UP);

上面的代码则是保留两位小数,采用HALF_UP模式(四舍五入)

八、时间和日期

1. Date

用于获取当前时间和其对应的时间毫秒值

java开发用ide还是android studio_开发语言_07

public class Test{
    public static void main(String[] args) {
        Date d1 = new Date();
        System.out.println(d1);  // Mon Sep 25 16:20:34 CST 2023

        long time = d1.getTime();
        System.out.println(time);// 1695630034924

        time += 60*1000;         // 获取一分钟后的时间
        Date d2 = new Date(time);// Mon Sep 25 16:21:34 CST 2023
        System.out.println(d2);

        d1.setTime(time);
        System.out.println(d1);  // 和上面一样
    }
}

2. SimpleDateFormat

用于把时间日期数据格式化和解析字符串中的时间对象

java开发用ide还是android studio_开发语言_08

public class Test{
    public static void main(String[] args) {
        Date d1 = new Date();
        System.out.println(d1);  // Mon Sep 25 16:20:34 CST 2023
        long time = d1.getTime();

        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEEa");// 要输入时间格式
        String rs1 = s.format(d1);
        System.out.println(rs1);// 2023-09-25 16:42:38 周一下午
        String rs2 = s.format(time);
        System.out.println(rs2);// 同上
    }
}

注意:创建 SimpleDateFormat 对象时,要输入正确的时间格式的参数,如:yyyy-MM-dd HH:mm:ss EEEa(其中对应的字母代表【年-月-日 时:分:秒 星期几 上/下午】)

java开发用ide还是android studio_开发语言_09

public class Test{
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");// 要输入时间格式
        String time = "2023-08-25";

        Date d = s.parse(time);
        System.out.println(d);// Fri Aug 25 00:00:00 CST 2023
    }
}

注意:1)解析的字符串要与创建的 SimpleDateFormat 对象设置的时间格式要相同

           2)调用 parse 方法抛出异常,即 throws ParseException

3. Calendar

用于获取当前日历对象,可以自由修改年月日时分秒

java开发用ide还是android studio_开发语言_10

public class Test{
    public static void main(String[] args) {
        Calendar now = Calendar.getInstance();
        System.out.println(now);

        int year = now.get(Calendar.YEAR);
        System.out.println(year);// 2023

        Date d = now.getTime();
        System.out.println(d);    // Mon Sep 25 18:07:48 CST 2023

        long time = now.getTimeInMillis();
        System.out.println(time); // 1695636525522

        now.set(Calendar.MONTH,9);// Calendar中的MONTH是从0开始计算的
        now.set(Calendar.DAY_OF_MONTH,31);

        now.add(Calendar.MONTH,2);
        now.add(Calendar.DAY_OF_MONTH,-30);
    }
}

注意:1)使用 getInstance 获取 Calendar 的子类时,获取的永远是当前的日期时间

           2)使用 set、add 等方法修改时间时,如果超出设置量的范围,则会自动转换为正常的日期时间,不会出现日期错误等问题

九、高级时间日期

1. LocalDate,LocalTime,LocalDateTime

LocalDate:代表本地日期(年、月、日、星期)

LocalTime:代表本地时间(时、分、秒、纳秒)

LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)

1)LocalDate 常用方法

常用于获取和修改当前日期或指定日期

public class Test{
    public static void main(String[] args) {
        LocalDate ld = LocalDate.now(); // 2023-09-27

        int year = ld.getYear();
        int month = ld.getMonthValue();
        int day = ld.getDayOfMonth();
        int dayOfYear = ld.getDayOfYear();
        int dayOfWeek = ld.getDayOfWeek().getValue();
        System.out.println(year+"-"+month+"-"+day);  // 2023-9-27
        System.out.println("今天是今年第"+dayOfYear+"天"+"  星期"+dayOfWeek); // 今天是今年第270天  星期3
        // 设置指定的年月日
        LocalDate ld1 = ld.withYear(2077).withMonth(12).withDayOfMonth(30); // 2077-12-30
        // 对年月日进行加减操作
        LocalDate ld2 = ld.plusYears(2).plusMonths(2).plusDays(3);// 2025-11-30
        LocalDate ld3 = ld.minusYears(2).minusMonths(2).minusDays(3);// 2021-07-24
        // 获取指定日期的对象
        LocalDate ld4 = LocalDate.of(2077,1,1);
        // 比较两个日期
        System.out.println(ld.equals(ld4));  // false
        System.out.println(ld.isBefore(ld4));// true
        System.out.println(ld.isAfter(ld4)); // false
    }
}

2)LocalTime 常用方法

常用于获取和修改当前时间或指定时间

public class Test{
    public static void main(String[] args) {
        LocalTime lt = LocalTime.now(); // 10:47:19.042974700

        int hour = lt.getHour();
        int minute = lt.getMinute();
        int second = lt.getSecond();
        int nano = lt.getNano();
    }
}

其他操作与 LocalDate 基本相同,这里不再演示

3)LocalDateTime 常用方法

常用于获取和修改当前日期时间或指定日期时间

public class Test{
    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.now(); // 2023-09-27T10:56:36.804232400
        
        // LocalDate,LocalTime与LocalDateTime之间类型转换
        LocalDate ld = ldt.toLocalDate(); // 2023-09-27
        LocalTime lt = ldt.toLocalTime(); // 10:56:36.804232400
        LocalDateTime ldt1 = LocalDateTime.of(ld,lt); // 2023-09-27T10:56:36.804232400
    }
}

其他操作与 LocalDate,LocalDate 基本相同,这里不再演示

注意:1)这三种类提供的方法都可以实现链式编程

           2)如果要修改指定的日期时间,修改的日期时间必须在正常的范围内

2. ZoneId,ZonedDateTime

ZoneId:代表时区Id

ZonedDateTime:代表带时区的日期时间

public class Test{
    public static void main(String[] args) {
        // 获取系统的默认时区(【洲名/城市名】或【国家名/城市名】)
        ZoneId zoneId = ZoneId.systemDefault(); // Asia/Shanghai
        String id = zoneId.getId(); // Asia/Shanghai
        // 获取Java支持的全部时区对象
        System.out.println(ZoneId.getAvailableZoneIds());
        // 获取指定的时区对象
        ZoneId zoneId1 = ZoneId.of("America/New_York");
        // 获取指定时区的日期时间对象
        // America/New_York UTC-4:00
        ZonedDateTime zdt = ZonedDateTime.now(zoneId1); // 2023-09-26T23:25:18.970548-04:00[America/New_York]
        // Asia/Shanghai UTC+8:00
        ZonedDateTime zdt1 = ZonedDateTime.now(); // 2023-09-27T11:26:20.253267400+08:00[Asia/Shanghai]
        // 国际标准时间 UTC
        ZonedDateTime zdt2 = ZonedDateTime.now(Clock.systemUTC()); // 2023-09-27T03:31:28.345425Z
    }
}

ZonedDateTime 的其他操作与 LocalDateTime 基本相同,这里不再演示

3. Instant 

代表时间线,可以获取从1970-01-01 00:00:00 到当前时间的总秒数+不到一秒的纳秒数

public class Test{
    public static void main(String[] args) {
        Instant i = Instant.now();
        System.out.println(i); // 2023-09-27T08:31:23.877134900Z
        long second = i.getEpochSecond(); // 1695802628 (s)
        int nano = i.getNano(); // 854942100 (ns)
        // 增加或减少 秒、毫秒、纳秒
        Instant i1 = i.plusSeconds(10).plusMillis(10).plusNanos(10); // 2023-09-27T08:31:33.887134910Z
        Instant i2 = i.minusSeconds(10).minusMillis(10).minusNanos(10); // 2023-09-27T08:31:13.867134890Z
        // 比较两个时间线
        System.out.println(i1.equals(i2));  // false
        System.out.println(i1.isBefore(i2));// false
        System.out.println(i1.isAfter(i2)); // true
    }
}

常用于记录代码的执行时间,或用于记录用户操作某个事件的时间点

4. DateTimeFormatter

用于对日期时间对象进行格式化或解析字符串中的日期时间

public class Test{
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        LocalDateTime ldt = LocalDateTime.now(); // 2023-09-27T17:00:20.818131300
        // 格式化对象
        String rs = formatter.format(ldt); // 正向格式化
        System.out.println(rs); // 2023-09-27 17:00:20
        String rs1 = ldt.format(formatter);// 反向格式化
        System.out.println(rs1);// 2023-09-27 17:00:20
        // 解析字符串
        String rs2 = "2077-10-01 12:23:44";
        LocalDateTime ldt1 = LocalDateTime.parse(rs2,formatter); // 2077-10-01T12:23:44
    }
}

注意:被解析的字符串格式要与格式化器的时间格式保持一致

5. Period,Duration

1)Period(一段时期)

可以计算两个 LocalDate 对象相差的年数、月数、天数,支持 LocalDate

public class Test{
    public static void main(String[] args) {
        LocalDate ld1 = LocalDate.of(2023,10,28);
        LocalDate ld2 = LocalDate.of(2077,12,1);

        Period p = Period.between(ld1,ld2);
        System.out.println(p.getYears()); // 53
        System.out.println(p.getMonths());// 1
        System.out.println(p.getDays());  // 3
    }
}

注意:Period 的日期间隔只计算一位间隔,且遵循借位原则

2)Duration(持续时间)

可以计算两个时间对象相差的天数、小时数、分数、秒数、毫秒数、纳秒数;支持 LocalTime、LocalDateTime、 Instant 等时间。

public class Test{
    public static void main(String[] args) {
        LocalDateTime ldt1 = LocalDateTime.of(2023,10,1,12,12,12,12);
        LocalDateTime ldt2 = LocalDateTime.of(2023,12,12,11,11,11,11);

        Duration duration = Duration.between(ldt1,ldt2);
        System.out.println(duration.toDays());   // 71
        System.out.println(duration.toHours());  // 1726
        System.out.println(duration.toMinutes());// 103618
        System.out.println(duration.toSeconds());// 6217138
        System.out.println(duration.toMillis()); // 6217138999
        System.out.println(duration.toNanos());  // 6217138999999999
    }
}

注意:Duration 的时间间隔是计算整体的间隔

十、Arrays 类

1.认识 Arrays

Arrays 类是一个操作数组的工具类

java开发用ide还是android studio_bc_11

public class Test{
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5,6};
        // 将数组转换为字符串类型
        String arrStr = Arrays.toString(arr);
        System.out.println(arrStr); // [1, 2, 3, 4, 5, 6]
        // 拷贝指定范围的数组
        int[] arr1 = Arrays.copyOfRange(arr,1,3);// 包前不包后
        System.out.println(Arrays.toString(arr1)); // [2, 3]
        // 拷贝指定大小的数组
        int[] arr2 = Arrays.copyOf(arr,10);
        System.out.println(Arrays.toString(arr2)); // [1, 2, 3, 4, 5, 6, 0, 0, 0, 0]
        // 将数组中的原数据改为新数据
        double[] arr3 = new double[]{99.8,22.6,100};
        Arrays.setAll(arr3, new IntToDoubleFunction(){
            @Override
            public double applyAsDouble(int value) {
                return BigDecimal.valueOf(arr3[value]).multiply(BigDecimal.valueOf(0.8)).doubleValue();
            }
        });
        System.out.println(Arrays.toString(arr3)); // [79.84, 18.08, 80.0]
        // 将数组中的数进行排序(默认为升序)
        Arrays.sort(arr3);
        System.out.println(Arrays.toString(arr3)); // [18.08, 79.84, 80.0]
    }
}

注意:1)copyOfRange 和 copyOf 方法所拷贝的数组都是浅拷贝

           2)对浮点型计算一定要注意失真问题,在必要的时候使用 BigDecimal

           3)在示例中的 sort 方法只是对数进行了简单排序,它也可以把对象排序

2. sort 方法(排序对象)

方式一:让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。

public class Student implements Comparable<Student>{
    private String name;
    private double height;
    private int age;

    // 重写compareTo方法,制定排序的比较规则,sort方法会自动调用compareTo方法
    // 升序规定1:左边对象(this)大于右边对象(o),返回正整数
    // 升序规定2:左边对象(this)小于右边对象(o),返回负整数
    // 升序规定3:左边对象(this)等于右边对象(o),返回0
    @Override
    public int compareTo(Student o) {
        //if(this.age>o.age) {
        //    return 1;
        //}
        //else if (this.age<o.age) {
        //    return -1;
        //}
        //return 0;
        return this.age-o.age;
    }

    public Student(String name, double height, int age) {
        this.name = name;
        this.height = height;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getHeight() {
        return height;
    }
    public void setHeight(double height) {
        this.height = height;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", age=" + age +
                '}';
    }
}

注意: 1)Comparable 是一个泛型接口,需要传入类型

            2)在外部调用 sort 方法会自动调用类内的 compareTo 方法

            3)compareTo 方法中,示例注释的倒序规定与升序规定同理,交换顺序即可

            4)如果比较的标准为整型,可以直接返回相减的结果,浮点型不能

方式二:使用 sort 方法,创建 Comparator 比较器接口的匿名内部类对象,然后制定比较规则

public class Test{
    public static void main(String[] args) {
        Student[] students = new Student[4];
        students[0] = new Student("a",143.9,18);
        students[1] = new Student("b",123.3,13);
        students[2] = new Student("c",187.4,19);
        students[3] = new Student("d",155.2,18);

        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(), o2.getHeight());
            }
        });
        System.out.println(Arrays.toString(students));
    }
}

注意:1)Comparator 是一个泛型接口,要传入类型

           2)它的比较规则和方法一相同,这里不再重复

           3)如果比较的标准为浮点型,可以使用 Double 包装类的 compare 方法来返回结果

十一、方法引用

作用:不暴露实现方法和传入参数,并且能已改全改解耦合(目前只做了解)

标志性符号:【: :】(双冒号)

1.静态方法的引用

静态方法的引用:类名 :: 静态方法。

使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。

2.实例方法的引用

实例方法的引用:对象名 :: 实例方法。

使用场景:如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用。

3.特定类型方法的引用

特定类型的方法引用:类型 :: 方法

使用场景:如果某个 Lambda 表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的传入参数,则此时就可以使用特定类型方法引用。

4.构造器引用

构造器引用:类名::new。
使用场景:如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。

十二、正则表达式

1.认识正则表达式

概念:由一些特定的字符组成,代表一个规则。

作用:1)用来校验数据的格式是否合法

           2)在一段文本中查找符合规则的语句

2.书写规则

下面是一些基础规则:

java开发用ide还是android studio_java_12

java开发用ide还是android studio_System_13

java开发用ide还是android studio_字符串_14

public class Test {
    public static void main(String[] args) {
        System.out.println("a".matches("[a-z]"));// true
        System.out.println("1".matches("\\d"));  // true
        System.out.println("A".matches("\\w"));  // true
        System.out.println("2a".matches("\\w")); // false
        System.out.println("a3A".matches("[a-z]\\w{2,3}")); // true
        System.out.println("a3A".matches("[^a-z]\\w{2,3}"));// false
    }
}

注意:在Java中,\ 是有特殊含义的,如 \n、\t,所以书写部分字符时要使用 // 转义

下面还有一些常用的规则字符:

public class Test {
    public static void main(String[] args) {
        //    (?i)-忽略大小写    |-或    ()-分组
        System.out.println("Az".matches("(?i)[a-z]{2}"));    // true
        System.out.println("123".matches("\\d{3}|[a-z]{3}"));// true
        System.out.println("123".matches("\\d{3}|[a-z]{3}"));// true
        System.out.println("1a3".matches("\\d{3}|[a-z]{3}"));// false
    }
}

3.应用:查找文本中的指定内容

public class Test {
    public static void main(String[] args) {
        String data = "电话: 18512516758,18512508907\n" +
                "或者联系邮箱: boniu@itcast.cn\n" +
                "座机电话: 01036517895, 010-98951256\n" +
                "邮箱: bozai@itcast.cn\n" +
                "邮箱2: dlei0009@163.com\n" +
                "热线电话: 400-618-9090,400-618-4000,\n" +
                "4006184000,4006189090\n";
        // 1.编写正则表达式
        String regex = "(1[3-9]\\d{9})|(\\w{2,}@\\w{2,10}(\\.\\w{2,3}){1,2})"+
                "|(010-?\\d{5,10})|(\\d{3}-?\\d{3}-?\\d{4})";
        // 2.将正则表达式封装给一个Pattern对象
        Pattern pattern = Pattern.compile(regex);
        // 3.通过Pattern对象来得到查找指定内容的Matcher匹配器
        Matcher matcher = pattern.matcher(data);
        // 4.通过匹配器来爬取内容
        while(matcher.find())
        {
            System.out.println(matcher.group());
        }
    }
}

4.应用:对文本中的指定内容进行二次操作(替换,切割)

public class Test {
    public static void main(String[] args) {
        // 1.将文本中的非中文字符替换为“-”
        String data1 = "蔡徐坤3bkwjeiqk王一博ajwdh9672肖战";
        String s1 = data1.replaceAll("\\w+", "-");
        System.out.println(s1); // 蔡徐坤-王一博-肖战
        // 2.将文本中的重复字符替换单一字符
        String data2 = "我我我我喜欢编编编编程程程!!!!";
        String s2 = data2.replaceAll("(.)\\1+","$1");
        System.out.println(s2); // 我喜欢编程!
        // 3.将文本中的中文名字提取出来
        String data3 = "蔡徐坤3bkwjeiqk王一博ajwdh9672肖战";
        String[] names = data3.split("\\w+");
        System.out.println(Arrays.toString(names)); // [蔡徐坤, 王一博, 肖战]
    }
}

补充:1)实现替换操作:利用 String 类中的 replaceAll 方法,根据正则表达式来对指定内容替换,最后返回替换后的字符串

           2)对重复字符单一化操作时,可以使用 \\1 来对指定内容分组,用 $1 来引用

           3)实现分割操作:利用 String 类中的 split 方法,根据正则表达式以指定内容为分割符来分割文本,最后返回一个 String 数组

十三、异常

1.认识异常

概念:指程序出现的各种问题,存在于 java.lang.Throwable

分类:1)Error:代表系统级别异常,一般不需要程序员解决

           2)Exception:代表程序级别异常,是在编译阶段或者运行阶段的异常

           3)RuntimeException:RuntimeException及其子类是继承 Exception 类的,用于封装程序运行时的问题

异常处理:1)try{}catch{}语句

public class Test {
    public static void main(String[] args) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date d = sdf.parse("1999-12-30 12:12:12");
            System.out.println(d);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

                  2)throws 抛出异常

public class Test {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse("1999-12-30 12:12:12");
        System.out.println(d);
    }
}

2.自定义异常

1)自定义运行时异常

定义一个异常类并继承 RuntimeException,然后重写构造器

通过 throw new 异常类(xxx)来创建异常对象并抛出

public class NumIllegalRuntimeException extends RuntimeException{
    public NumIllegalRuntimeException() {
    }
    public NumIllegalRuntimeException(String message) {
        super(message);
    }
}
public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int number = sc.nextInt();
        checkNum(number);
    }
    public static void checkNum(int num)
    {
        if(num>0&&num<100) {
            System.out.println("输入正确");
        }
        else {
            throw new NumIllegalRuntimeException("This number is illegal,"+ num +" is error");
        }
    }
}

java开发用ide还是android studio_java_15

注意: 自定义运行时异常反应不强烈,只有在运行时才会报错

2)自定义编译时异常

定义一个异常类并继承 Exception,然后重写构造器

通过 throw new 异常类(xxx)来创建异常对象并抛出

public class NumIllegalException extends Exception{
    public NumIllegalException() {
    }
    public NumIllegalException(String message) {
        super(message);
    }
}
public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int number = sc.nextInt();
        checkNum(number);
    }
    public static void checkNum(int num) throws NumIllegalException {
        if(num>0&&num<100) {
            System.out.println("输入正确");
        }
        else {
            throw new NumIllegalException("This number is illegal,"+ num +" is error");
        }
    }
}

注意:自定义运行时异常反应强烈,在编译时就会报错,需要抛出异常才能运行

3.异常处理

将底层方法的异常逐层往上抛,直到全部抛到顶层方法中后集中处理

处理方法:1)捕获异常,记录异常并响应合适的信息给用户

public class Test {
    public static void main(String[] args) {
        try {
            test1();
        } catch (Exception e) {
            System.out.println("您当前操作有问题");
            e.printStackTrace();
        }
    }
    public static void test1() throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse("2028-11-11 10:24");
        System.out.println(d);
        test2();
    }
    public static void test2 () throws Exception {
        InputStream is = new FileInputStream("D:/meinv. png");
    }
}

注意:优先识别并捕获高层方法的异常进行处理

                  2)捕获异常,尝试重新修复

public class Test {
    public static void main(String[] args) {
        while(true){
            try {
                checkNum();
                break;
            } catch (Exception e) {
                System.out.println("输入数字不合法");
            }
        }
    }
    public static void checkNum(){
        Scanner sc = new Scanner(System.in);
        System.out.println("请你输入一个正整数:");
        int number = sc.nextInt();
        while (true) {
            if(number>0) {
                System.out.println("输入正确");
            }
            else {
                System.out.println("输入错误");
            }
        }
    }
}

将捕获异常套入循环,出现异常后再次循环,直到运行成功