Java 学习 - Day 13

1、字符串

1.1、String

        在Java中,String 是一个特殊的类,位于 java.lang 包下。它代表了一系列字符的有序集合,即我们通常所说的字符串。String 类型的对象用于存储和操作文本数据

        String 所具备的一些关键特性如下:

                1、不可变性:String 的底层是被final 修饰的char 数组(名称是value),一旦一个 String 对象被创建,它的内容就不能更改。如果尝试修改一个字符串,实际上会创建一个新的字符串对象。这种不可变性有助于提高多线程环境下的安全性,并且支持字符串常量池的高效实现

                2、字符串池:为了节省内存,Java使用了字符串池来存储字符串字面量。当创建新的字符串时,如果字符串池中已经存在一个等价的字符串,则会返回池中已存在的字符串的引用。
                3、创建方式:字符串字面量:如 String s = "Hello";

                                        使用 new 关键字:如 String s = new String("Hello"); (这种方式不会利用字符串池中的现有实例)
                                        使用其他构造器或静态方法,比如 String.valueOf()。
                4、字符串操作:String 类提供了许多方法来操作字符串,如 concat() 用于连接字符串,substring() 用于获取子字符串,indexOf() 和 lastIndexOf() 用于查找字符或子字符串的位置,replace() 用于替换字符或子字符串,split() 用于根据正则表达式分割字符串等等

                5、不可继承:String 类被声明为 final,这意味着它不能被继承。final 关键字防止了任何类从 String 继承,确保了 String 类的实现细节不会被外部类改变,从而保证了 String 类的一致性和安全性

        通常来说,只要是实用双引号括起来的都属于一个String 对象。而字符串中的字符使用Unicode 编码集,一个字符占用两个字节


        在Java中,创建 String 对象可以通过两种主要的方式:直接赋值和使用 new 关键字。这两种方式之间有几个重要的区别:

        1、如果使用直接赋值的方式来创建一个字符串时,实际上是创建了一个指向字符串常量池中的一个字符串对象的引用。如果字符串常量池中已经存在一个具有相同内容的字符串,那么将会重用那个字符串对象,而不是创建一个新的对象。这种方式可以提高效率并减少内存消耗

String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);  // 输出 true

        2、如果使用 new 关键字创建一个 String 对象时,无论字符串池中是否存在相同的字符串,都会在堆内存中创建一个新的对象。这会导致即使两个字符串的内容完全相同,它们在内存中的地址也会不同

String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);  // 输出 false


        String 类有一个 intern() 方法,它可以将一个字符串对象添加到字符串池中。如果字符串池中已经存在一个与指定字符串相同的字符串,则返回字符串池中的字符串引用;否则,将新字符串添加到池中,并返回该字符串的引用

String str1 = new String("hello");
String str2 = "hello";
String str3 = str1.intern();
System.out.println(str1 == str2);  // 输出 false
System.out.println(str3 == str2);  // 输出 true


        在Java中,两个字符串对象相加(通过 + 操作符)和两个字符串字面量相加之间的行为有所不同

        1、当两个字符串字面量相加时,Java编译器会在编译时尽可能优化这个操作。如果两个字符串字面量是在同一个表达式中相加,并且它们都在编译期是确定的,那么编译器会直接计算出结果,并将其作为一个单独的字符串字面量放入字符串常量池中

        2、当两个字符串对象相加时,情况就不同了。每次使用 + 操作符时,都会创建一个新的 String 对象。这是因为 + 操作符在Java中实际上是一个特殊的运算符,它会调用 StringBuilder 或 StringBuffer 类来构建新的字符串,然后返回一个新的 String 对象


        String 类在 Java 中提供了许多常用的方法,用于处理字符串的各种操作。以下是一些常用的 String 方法及其说明:

// 1、字符串比较
// equals(Object obj):比较当前字符串与另一个对象是否相等(内容相同)。
String s1 = "hello";
String s2 = "hello";
boolean isEqual = s1.equals(s2);  // 返回 true

// equalsIgnoreCase(String anotherString):忽略大小写比较两个字符串是否相等.
String s1 = "Hello";
String s2 = "hello";
boolean isEqualIgnoreCase = s1.equalsIgnoreCase(s2);  // 返回 true

// compareTo(String anotherString):比较当前字符串与另一个字符串的字典顺序。
String s1 = "apple";
String s2 = "banana";
int comparisonResult = s1.compareTo(s2);  // 返回负数,表示 s1 在字典顺序上小于 s2

// 2、字符串查询
// charAt(int index):获取指定索引处的字符。
String s = "hello";
char c = s.charAt(1);  // 返回 'e'

// indexOf(String str):返回指定子字符串首次出现的索引。
String s = "hello world";
int index = s.indexOf("world");  // 返回 6

// lastIndexOf(String str):返回指定子字符串最后一次出现的索引。
String s = "hello hello";
int index = s.lastIndexOf("hello");  // 返回 6

// startsWith(String prefix):检查当前字符串是否以指定前缀开头。
String s = "hello world";

// contains(CharSequence s):判断字符串是否包含指定的子字符串。
String s = "hello world";
boolean contains = s.contains("world");  // 返回 true

// 3、字符串转换
// toUpperCase():将字符串转换为大写。
String s = "hello";
String upperCase = s.toUpperCase();  // 返回 "HELLO"

// toLowerCase():将字符串转换为小写。
String s = "HELLO";
String lowerCase = s.toLowerCase();  // 返回 "hello"

// trim():删除字符串两端的空白字符。
String s = "  hello  ";
String trimmed = s.trim();  // 返回 "hello"

// 4、 字符串分割
// split(String regex):按照指定的正则表达式分割字符串。
String s = "a,b,c,d";
String[] parts = s.split(",");  // 返回 ["a", "b", "c", "d"]

// 5、字符串替换
// replace(char oldChar, char newChar):替换字符串中的指定字符。
String s = "hello";
String replaced = s.replace('l', 'L');  // 返回 "heLLo"

// 6、字符串拼接
// concat(String str):将指定字符串拼接到当前字符串末尾。
String s1 = "hello";
String s2 = " world";
String concatenated = s1.concat(s2);  // 返回 "hello world"

// 7、字符串长度
// length():返回字符串的长度。
String s = "hello";
int length = s.length();  // 返回 5

// 8、子字符串提取
// substring(int beginIndex):从指定索引开始提取子字符串。
String s = "hello world";
String substring = s.substring(6);  // 返回 "world"

// substring(int beginIndex, int endIndex):从指定索引开始到指定索引结束截取子字符串。
String s = "hello world";
String sub = s.substring(6, 11);  // 返回 "worl"


        除了以上方法之外,在 Java 中,字符串格式化是一种常见的需求,用于生成格式化的字符串输出。Java 提供了多种方法来进行字符串格式化,包括使用 String.format() 方法、Formatter 类以及 MessageFormat 类等

        1、String.format() 方法是一种非常灵活且强大的字符串格式化工具。它可以用来生成各种格式化的字符串

String name = "Alice";
int age = 25;
double height = 1.75;

// 格式化字符串
String formattedString = String.format("Name: %s, Age: %d, Height: %.2f", name, age, height);

System.out.println(formattedString);  // 输出 "Name: Alice, Age: 25, Height: 1.75"

        2、Formatter 类提供了类似 C 语言中的 printf 格式化字符串的功能

String name = "Alice";
int age = 25;
double height = 1.75;

Formatter formatter = new Formatter();
String formattedString = formatter.format("Name: %s, Age: %d, Height: %.2f", name, age, height).toString();

System.out.println(formattedString);  // 输出 "Name: Alice, Age: 25, Height: 1.75"

        3、MessageFormat 类提供了国际化的字符串格式化功能,可以方便地进行多语言支持

String template = "Name: {0}, Age: {1}, Height: {2}";
Object[] arguments = {"Alice", 25, 1.75};

String formattedString = MessageFormat.format(template, arguments);

System.out.println(formattedString);  // 输出 "Name: Alice, Age: 25, Height: 1.75"

        


1.2、StringBuffer

        java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行修改。很多方法与String 相同,最大的区别在于StringBuffer 是可变长度的

        其父类AbstractStringBuilder 是一个抽象类 ,提供了StringBuffer 的基础实现。其中存有char 类型数组value,不使用final 修饰,相当于存储的是一个变量,修改其中内容的时候不需要每次都更新地址(即创建新的对象),效率就会提高

        StringBuffer 具有缓冲区机制,其体现在以下两方面:

                1、初始容量:StringBuffer 的默认初始容量是 16 个字符,也可以通过构造器指定初始容量

                2、自动扩容:当 StringBuffer 的长度超过当前容量时,会自动扩容。默认情况下,每次扩容会增加当前容量的 50%

                3、确保容量:ensureCapacity(int minimumCapacity):确保 StringBuffer 的容量至少至少等于指定的最小值。如果当前容量小于参数,则分配具有更大容量的新内部数组。新容量是以下容量中较大的一个:
                        ● 参数 minimumCapacity 。
                        ● 是旧容量的两倍,再加上 2。

public class StringBufferExample {
    public static void main(String[] args) {
        // 创建一个初始容量为 16 的 StringBuffer
        StringBuffer sb = new StringBuffer("hello");

        // 追加字符串
        sb.append(" world");
        System.out.println("After append: " + sb.toString()); // After append: hello world
        System.out.println("Capacity: " + sb.capacity());// Capacity: 21(16 + 5)

        // 再次追加字符串,触发扩容
        sb.append(" more text");
        System.out.println("After append again: " + sb.toString()); // After append again: hello world more text
        System.out.println("Capacity: " + sb.capacity()); // Capacity: 34

        // 确保容量至少为 50
        sb.ensureCapacity(50);
        System.out.println("After ensureCapacity: " + sb.toString()); // After ensureCapacity: hello world more text
        System.out.println("Capacity: " + sb.capacity());// Capacity: 50(34 * 2 + 2)
    }
}


        在 Java 中,String 和 StringBuffer 之间的转换非常常见,以下是几种常见的转换方式:

                1、从 String 转换到 StringBuffer

// 1、使用 StringBuffer 的构造器
String str = "hello";
StringBuffer sb = new StringBuffer(str);

// 2、使用 append 方法
String str = "hello";
StringBuffer sb = new StringBuffer();
sb.append(str);

                2、从 StringBuffer 转换到 String

// 使用 toString 方法
StringBuffer sb = new StringBuffer("hello");
String str = sb.toString();


        StringBuffer 是 Java 中用于处理可变字符串的一个类,它提供了许多方法来操作字符串。这些方法使得 StringBuffer 成为一个强大的工具,常用方法如下:

        

public class StringBufferExample {
    public static void main(String[] args) {
        // 创建一个初始容量为 21 的 StringBuffer
        StringBuffer sb = new StringBuffer("hello");

        // 追加字符串
        sb.append(" world");
        // After append: hello world
        System.out.println("After append: " + sb.toString());

        // 插入字符串
        sb.insert(6, "there ");
        // After insert: hello there world
        System.out.println("After insert: " + sb.toString());

        // 删除字符串
        sb.delete(6, 12);
        // After delete: hello world
        System.out.println("After delete: " + sb.toString());

        // 替换字符串
        sb.replace(6, 11, "there");
        // After replace: hello there
        System.out.println("After replace: " + sb.toString());

        // 反转字符串
        sb.reverse();
        // After reverse: ereht olleh
        System.out.println("After reverse: " + sb.toString());

        // 获取字符
        char c = sb.charAt(1);
        // Char at index 1: r
        System.out.println("Char at index 1: " + c);

        // 查找子字符串
        int index = sb.indexOf("ere");
        // Index of 'ere': 0
        System.out.println("Index of 'ere': " + index);

        // 设置长度
        sb.setLength(3);
        // After set length: ere
        System.out.println("After set length: " + sb.toString());

        // 获取容量
        int capacity = sb.capacity();
        // Capacity: 21
        System.out.println("Capacity: " + capacity);

        // 确保容量
        sb.ensureCapacity(20);
        // After ensure capacity: 21
        System.out.println("After ensure capacity: " + sb.capacity());

        // 转换为字符串
        String str = sb.toString();
        // Converted to String: ere
        System.out.println("Converted to String: " + str);
    }
}

1.3、StringBuilder

        与StringBuffer 类似,也是一个可变的字符序列,同样是AbstractStringBuilder 的一个子类,提供与StringBuffer 兼容的API,但是不保证同步(StringBuilder 不是线程安全的,区别在于StringBuffer 中的方法都使用synchronized 修饰),被设计为StringBuffer 的一个简易替换,用于在但线程使用的时候。建议优先使用StringBuilder,因为它比StringBuffer 的操作要快

        

拼接优化

        当字符串字面量与变量进行拼接时,Java 编译器会将整个表达式转化为 StringBuilder 或 StringBuffer 的操作。具体来说,编译器会生成临时的 StringBuilder 或 StringBuffer 对象来执行拼接操作,而最终的结果会被转换成 String 类型

     这种优化使得字符串拼接更加高效,并且能够处理复杂的拼接逻辑。对于简单的字符串拼接,编译器会自动选择合适的优化策略


1.4、比较

        String、StringBuffer 和 StringBuilder 都是用来表示字符串的类,但在 Java 中它们有一些重要的区别。这些区别主要体现在性能、线程安全性和不可变性等方面。下面是它们之间的主要区别:

       1. 不可变性 vs 可变性
                String:String 类表示的是不可变字符串。这意味着一旦一个 String 对象被创建,它的内容就不能被改变。任何试图修改 String 对象的行为都会导致创建一个新的 String 对象。这使得 String 对象非常适合用于共享,例如作为哈希表的键。
                StringBuffer 和 StringBuilder:这两个类都表示可变字符串。这意味着你可以修改它们的内容而不必创建新的对象。这对于需要频繁修改字符串的场合非常有用。

        2. 线程安全性
                StringBuffer:StringBuffer 是线程安全的,它的所有修改方法都是同步的(synchronized)。这意味着在多线程环境中可以安全地使用 StringBuffer,而不需要额外的同步措施。
                StringBuilder:StringBuilder 是非线程安全的,它的方法没有被同步。这意味着在单线程环境中使用 StringBuilder 更高效,但在多线程环境中使用时需要手动同步。
                String:由于 String 是不可变的,因此它是天然线程安全的。一旦创建,它的内容就不会改变,所以多个线程可以安全地共享一个 String 对象。
        3. 性能
                StringBuilder:由于 StringBuilder 的方法没有被同步,因此在单线程环境中使用 StringBuilder 通常比使用 StringBuffer 更高效。
                StringBuffer:虽然 StringBuffer 提供了线程安全,但由于方法的同步开销,它的性能通常低于 StringBuilder。
                String:由于 String 是不可变的,任何对 String 的修改操作都会导致创建新的 String 对象,这会导致更多的内存分配和垃圾回收压力,因此性能通常最低。
        4. 使用场景
                String:适用于不需要修改的字符串,如配置文件中的键值、数据库查询语句的一部分等。
                StringBuffer:适用于多线程环境下的字符串构建和修改操作。
                StringBuilder:适用于单线程环境下的字符串构建和修改操作。

        总的来说:String:不可变字符串,适合用于共享和作为键值。
                          StringBuffer:可变字符串,线程安全,适合多线程环境。
                          StringBuilder:可变字符串,非线程安全,适合单线程环境,性能较高。

2、常用类

1.1、Math

        Math 类是 Java 中的一个内置类,提供了许多数学运算的方法。这些方法包括基本的数学运算、三角函数、指数函数等。一些常用方法如下:

  • abs(double a) / abs(float a) / abs(int a) / abs(long a):返回绝对值。
  double absValue = Math.abs(-5.0);
  System.out.println(absValue);  // 输出 5.0
  • pow(double a, double b):计算 a 的 b 次方。
  double power = Math.pow(2, 3);
  System.out.println(power);  // 输出 8.0
  • sqrt(double a):计算平方根。
  double squareRoot = Math.sqrt(16);
  System.out.println(squareRoot);  // 输出 4.0
  • round(double a) / round(float a):四舍五入到最接近的整数。
  int rounded = Math.round(5.7);
  System.out.println(rounded);  // 输出 6
  • ceil(double a):向上取整。
  double ceilValue = Math.ceil(5.2);
  System.out.println(ceilValue);  // 输出 6.0
  • floor(double a):向下取整。
  double floorValue = Math.floor(5.8);
  System.out.println(floorValue);  // 输出 5.0
  • random():生成一个介于 0(含)和 1(不含)之间的随机数。
  double randomValue = Math.random();
  System.out.println(randomValue);  // 输出一个介于 0 和 1 之间的随机数

1.2、Arrays

        java.util.Arrays 类提供了许多静态方法来操作数组,包括排序、搜索、复制、填充等。一些常用方法如下:

  •  toString(Object[] a),将数组转换为字符串形式,便于输出和调试。
Integer[] integers = {1, 2, 3};
System.out.println(Arrays.toString(integers));  // 输出 [1, 2, 3]
  • sort(T[] a),对数组进行排序,默认为升序。
Integer[] integers = {3, 1, 2};
Arrays.sort(integers);
System.out.println(Arrays.toString(integers));  // 输出 [1, 2, 3]
  • sort(T[] a, Comparator<? super T> c),对数组进行自定义排序。
Integer[] integers = {3, 1, 2};
Arrays.sort(integers, new Comparator<Integer>() {
   @Override
   public int compare(Integer o1, Integer o2) {
        return o2 - o1;
      }
});

// [3, 2, 1]
System.out.println(Arrays.toString(integers));
  •  binarySearch(T[] a, T key),对已排序的数组执行二分搜索。
Integer[] integers = {1, 2, 3};
int index = Arrays.binarySearch(integers, 2);
System.out.println(index);  // 输出 1
  • fill(T[] a, T val),用指定的值填充数组。
Integer[] integers = new Integer[3];
Arrays.fill(integers, 1);
System.out.println(Arrays.toString(integers));  // 输出 [1, 1, 1]
  • copyOf(T[] original, int newLength),复制数组
Integer[] integers = {1, 2, 3};
Integer[] copy = Arrays.copyOf(integers, 5);
Arrays.fill(copy, 3, 5, 0); // 3, 4
System.out.println(Arrays.toString(copy));  // 输出 [1, 2, 3, 0, 0]
  • copyOfRange(T[] original, int from, int to),复制数组的一部分。
Integer[] integers = {1, 2, 3, 4, 5};
Integer[] copy = Arrays.copyOfRange(integers, 1, 4);
System.out.println(Arrays.toString(copy));  // 输出 [2, 3, 4]
  •  asList(T... a),将数组转换为 List 集合。
Integer[] integers = {1, 2, 3};
List<Integer> list = Arrays.asList(integers);
System.out.println(list);  // 输出 [1, 2, 3]

1.3、System

        System 类在 Java 中提供了许多静态方法用于执行与系统相关的操作,如系统属性访问、输入输出流重定向、垃圾回收请求等。一些常用方法如下:

  • currentTimeMillis(): 返回当前时间(从 1970 年 1 月 1 日 00:00:00 UTC 到现在的毫秒数)
    long currentTime = System.currentTimeMillis();
  • gc(): 请求 JVM 进行垃圾收集,但具体何时执行由 JVM 决定
     System.gc();  // 请求进行垃圾收集
  • arraycopy(Object src, int srcPos, Object dest, int destPos, int length): 将一个数组中的元素复制到另一个数组中
     int[] sourceArray = {1, 2, 3, 4, 5};
     int[] destArray = new int[5];
     System.arraycopy(sourceArray, 0, destArray, 0, sourceArray.length);
  • exit():退出当前程序
    System.exit(); // 退出程序

1.4、BigInteger & BigDecimal

        BigInteger 和 BigDecimal 是用于处理大数的类,它们提供了超越基本数据类型(如 int, long 等)所能表示范围的能力

        BigInteger
                1、适用于整数运算。
                2、可以存储任意大小的整数,只受限于可用内存。
                3、提供了丰富的数学运算方法,如加法、减法、乘法、除法等。
                4、支持模运算、指数运算以及一些高级操作如最大公约数(GCD)计算。


        BigDecimal
                1、适用于小数运算。
                2、不仅可以处理任意大小的小数,还能精确控制小数点后的位数。
                3、主要用于金融计算等需要高精度的场景。
                4、提供了四舍五入模式设置,可以自定义舍入规则。
                5、包含了加、减、乘、除等基本算术运算方法。


        使用场景
                BigInteger:当需要处理非常大的整数或进行密码学相关的计算时使用。
                BigDecimal:适合金融应用中的货币计算或其他需要精确到小数点后多位数的场景。

BigInteger num1 = new BigInteger("999999999999999999");
BigInteger num2 = new BigInteger("1000000000000000000");
        
BigInteger sum = num1.add(num2);
System.out.println("Sum: " + sum);
        
BigInteger product = num1.multiply(num2);
System.out.println("Product: " + product);

BigDecimal num1 = new BigDecimal("10.123456789");
BigDecimal num2 = new BigDecimal("20.987654321");
        
BigDecimal sum = num1.add(num2);
System.out.println("Sum: " + sum);

// 对于除法,可能出现无限循环小数,因此需要指定精度
BigDecimal quotient = num1.divide(num2, 2, RoundingMode.HALF_UP);
System.out.println("Quotient: " + quotient);

1.5、Date

        Date 是最早的日期类,位于 java.util 包中,它可以用来表示特定的瞬间,即从1970年1月1日00:00:00 GMT开始的毫秒数

import java.util.Date;

public class DateExample {
    public static void main(String[] args) {
        // 创建当前日期时间的 Date 对象
        Date now = new Date();
        System.out.println("Current Date: " + now);

        // 创建指定日期时间的 Date 对象
        long timestamp = 1679913600000L; // 2023-03-27 00:00:00 UTC
        Date specificDate = new Date(timestamp);
        System.out.println("Specific Date: " + specificDate);
    }
}

1.5.1、SimpleDateFormat

        SimpleDateFormat 是 DateFormat 的子类,它允许进行可格式化的日期/时间格式化和解析。可以使用构造函数指定日期格式的模式

import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample {
    public static void main(String[] args) {
        // 创建一个 Date 对象
        Date now = new Date();

        // 创建一个 SimpleDateFormat 对象,并指定日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 格式化日期
        String formattedDate = sdf.format(now);
        System.out.println("Formatted Date: " + formattedDate);

        // 解析字符串为日期
        try {
            Date parsedDate = sdf.parse(formattedDate);
            System.out.println("Parsed Date: " + parsedDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

        SimpleDateFormat 的日期格式模式由一系列字母和数字组成,这些字符代表不同的日期和时间组件。常见的模式字符包括:
                y:年份
                M:月份(注意,月份从1开始,不是0)
                d:一个月中的某一天
                H:一天中的小时数(24小时制)
                h:一天中的小时数(12小时制)
                m:分钟
                s:秒
                S:毫秒
                a:AM/PM标记
        例如,模式 "yyyy-MM-dd HH:mm:ss" 表示四位数的年份、月份、日期、24小时制的小时数、分钟和秒数。

1.5.2、Calendar

        Calendar类作为第二代日期类,提供了更丰富的日期和时间操作功能,通常与Date类配合使用。本身是一个抽象类(通过getInstance 方法获取其实例),它为特定瞬间与日历字段之间转换以及操作日历字段提供了方法

import java.util.Calendar;
import java.util.Date;

public class CalendarExample {
    public static void main(String[] args) {
        // 获取当前日期和时间的 Calendar 实例
        Calendar now = Calendar.getInstance();
        System.out.println("Current time in milliseconds: " + now.getTimeInMillis());

        // 设置日期
        now.set(Calendar.YEAR, 2023);
        now.set(Calendar.MONTH, Calendar.JANUARY); // 注意:月份是从0开始的,所以1月是0
        now.set(Calendar.DAY_OF_MONTH, 1);
        System.out.println("Set to: " + now.getTime());

        // 获取日期
        int year = now.get(Calendar.YEAR);
        int month = now.get(Calendar.MONTH); // 注意:月份是从0开始的
        int day = now.get(Calendar.DAY_OF_MONTH);
        System.out.println("Year: " + year + ", Month: " + month + ", Day: " + day);

        // 获取 Date 对象
        Date date = now.getTime();
        System.out.println("Date object: " + date);

        // 增加一个月
        now.add(Calendar.MONTH, 1);
        System.out.println("After adding one month: " + now.getTime());
    }
}

1.5.3、LocalDate~

        java.time包中的类(如LocalDate - 年月日、LocalTime - 时分秒、LocalDateTime等)提供了更现代且易于使用的API,也是第三代日期类,在JDK 8 推出

        前两代日期类存在的问题:

                1、JDK 1.0 中Date 的大部分方法在JDK 1.1 引入Calendar 之后被弃用

                2、像日期和时间应该是不变的

                3、Date 中的年份从1900 年开始且月份都是从0 月开始

                4、格式化只对Date 有效,没有专门针对Calendar 的格式化类

                5、不是线程安全的,且不能处理闰秒等(每隔2s 多出1s)

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class JavaTimeExample {
    public static void main(String[] args) {
        // 当前日期
        LocalDate today = LocalDate.now();
        System.out.println("Today's Date: " + today);

        // 当前时间
        LocalTime currentTime = LocalTime.now();
        System.out.println("Current Time: " + currentTime);

        // 当前日期时间
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("Current DateTime: " + currentDateTime);
    }
}

1.5.4、DateTimeFormatter

         Java 8 引入的一个新特性,用于格式化和解析 java.time 包下的日期时间类

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class DateTimeFormatterExample {
    public static void main(String[] args) {
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();

        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 格式化日期时间
        String formattedDate = now.format(formatter);

        // 输出格式化后的日期时间
        System.out.println("Formatted Date: " + formattedDate);
    }
}

        除了自定义格式,DateTimeFormatter 提供了一些预定义的格式器,这些格式器遵循 ISO 8601 标准

// yyyy-MM-dd'T'HH:mm:ss
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

        DateTimeFormatter 不仅能用来格式化日期时间,还能用来解析字符串为日期时间对象

String dateStr = "2024-09-20T17:06:00";
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
System.out.println("Parsed Date: " + dateTime);

1.5.5、Instant

        Instant 是 java.time 包中的一个接口,它代表时间线上某个时刻的瞬时点,通常以 Unix 时间戳的形式存储,即从 1970 年 1 月 1 日 UTC/GMT 开始的秒数。Instant 是与时区无关的,只表示精确的时间点

        可以通过Instant 获取当前时间戳,还可以对其进行操作,比如加上或者减去一些时间

Instant now = Instant.now();
System.out.println("Current Instant: " + now);

Instant plusSeconds = now.plus(Duration.ofSeconds(60));
System.out.println("Plus 60 seconds: " + plusSeconds);

        由于 java.util.Date 是基于 long 类型的时间戳(毫秒数),因此 Instant 和 Date 之间可以很容易地进行转换

import java.time.Instant;
import java.time.Duration;
import java.util.Date;

public class InstantExample {
    public static void main(String[] args) {
        // 获取当前时刻
        Instant now = Instant.now();
        System.out.println("Current Instant: " + now);

        // 加上60秒
        Instant plusSeconds = now.plus(Duration.ofSeconds(60));
        System.out.println("Plus 60 seconds: " + plusSeconds);

        // 将 Instant 转换为 Date
        Date dateFromInstant = Date.from(now);
        System.out.println("Date from Instant: " + dateFromInstant);

        // 将 Date 转换回 Instant
        Instant instantFromDate = dateFromInstant.toInstant();
        System.out.println("Instant from Date: " + instantFromDate);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值