JavaSE学习笔记day20

一、JDK8新特性

  • 接口中默认方法+静态方法 − 默认方法就是一个在接口里面有了一个实现的方法。静态方法就是接口中有个已经使用的静态方法,可直接调用

  • Lambda 表达式(拉姆达) − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

  • 方法引用 (Method Reference)− 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

    // ctrl + shift + k
    // ```java
    // 方法引用的代码
    System.out.println() ---> System::println();
    
  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。

  • Date Time API − 加强对日期与时间的处理。

二、关于接口的新特性

JDK8以后,允许接口中有被default和static修饰的方法带方法体

package com.qf.jdk.interface_;

public interface Demo1 {

    void m1();

    /**
     * 接口中设计方法带static,方法就可以有方法体
     * 但是子类不能重写!!
     * 但是可以通过接口名之间调用执行: Demo1.m3()
     * 子实现类不能调用!
     */
    static void m3(){
        System.out.println("这就是龙井!!!" );
    }

    // void clear();
    default void clear() {}

    /**
     * 因为接口中的抽象方法必须要重写!
     * 加了default的方法,有方法体,那就不是抽象方法
     * 那就不要求重写
     * ----------------------
     * 好处就是,在项目开发中,对已有的项目进行扩展时,比较优雅
     * 即,给接口设计了default修饰的方法后,所有子实现类并没有强制重写
     * 这样,就可以有选择对某个子实现类中重写该方法
     */
    default void m2(){
    }
}

三、Lambda表达式[重要]

Lambda 允许把函数(方法)作为一个方法的参数(函数作为参数传递到方法中)。


其实就是简化了匿名内部类的写法

3.1 初识lambda

package com.qf.jdk.lambda;

public class Demo1Lambda {

    public static void main(String[] args) {
        // 1 之前使用匿名内部类,开启线程
        new Thread(new Runnable( ) {
            @Override
            public void run() {
                System.out.println("匿名内部类开启线程" );
            }
        }).start();

        // 以上代码,主要关注的是线程的执行任务,即run()内部的代码

        // 2 换成lambda后
        new Thread(() -> System.out.println("lambda开启线程" )).start();

        // lambda基本结构是
        // () -> 语句
        // 参数列表,箭头符号,执行语句
    }
}

3.2 语法特点

能够使用lambda的前提是

  1. 方法得有参数
  2. 参数的必须是接口
  3. 接口中的方法只能有一个!!!
lambda就是对接口的抽象方法重写

new Thread(Runable run) Thread构造方法有参数

参数Runnable是接口

且Runnable接口内只有一个方法run


语法特征

(参数) -> {执行语句}
或者
参数  -> 执行语句
  • 参数圆括号,当参数是一个的时候,圆括号可加可不加

    • (x) -> System.out.println(x)
    • x -> System.out.println(x)
  • 参数圆括号,当参数是多个的时候,圆括号必须加

    • (x,y) -> System.out.println(x+y)
  • 参数数据类型可写可不写,编译时会自动推断是什么类型

    • (x) -> System.out.println(x)
    • (int x,String y) -> System.out.println(x+y)
  • 执行语句的花括号,当且仅当执行语句只有一句时,可以不加花括号

    • new Thread(() -> System.out.println("匿名内部类开启线程")).start();
      
  • 执行语句的花括号,当执行语句不只一句时,必须加花括号

    • new Thread(() -> {
               int a = 1;
               a++;
               System.out.println("lambda开启线程" );
           }).start();
      
  • 关于返回值

    • 如果方法有返回值,且执行语句只有一行语句时,可以不用写return,直接写值
    • 如果代码比较多,又要返回数据,就必须写上return

3.3 无参无返回值的lambda

lambda就是匿名内部类的简化.

package com.qf.jdk.lambda;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo2TestLambda {
    /**
     * lambda
     * 1 方法有参数
     * 2 参数是接口
     * 3 接口只有一个方法
     */
    public static void main(String[] args) {
        // 用匿名内部类来一遍
        m1(new M1( ) {
            @Override
            public void test1() {
                System.out.println("test1执行-无参无返回值" );
            }

        });

        // 改造成lambda
        m1(() -> System.out.println("lambda执行-无参无返回值" ));
    }

    public static void m1(M1 m1) {
        m1.test1();
    }
}

// 定义一个接口
// 像这种只能有一个抽象方法的接口,用于lambda的接口
// 称之为函数式接口
interface M1{
    void test1();
    // void test11();
}

3.4 有参数无返回值

package com.qf.jdk.lambda;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 有参无返回值的lambda
 */
public class Demo3TestLambda {
    /**
     * 1 方法有参数
     * 2 参数是接口
     * 3 接口只有一个抽象方法
     */

    public static void main(String[] args) {
        // 匿名内部类实现
        m2(10, new M2( ) {
            @Override
            public void test2(int a) {
                System.out.println(a*10);
            }
        });

        m22(8, "8", new M22( ) {
            @Override
            public void test22(int a, String b) {
                System.out.println(a+b);
            }
        });

        // lambda改造
        // 一个参数时,圆括号可以加
        m2(5,(a) -> System.out.println(a*10));
        // 一个参数时,圆括号也可以不加
        m2(6,a -> System.out.println(a*10));
        // 数据类型可加可不加
        m2(7,(int a) -> System.out.println(a*10));

        // 多个参数,圆括号必须加
        m22(9,"9",(a,b) -> System.out.println(a+b ));
        // 数据类型可加可不加
        m22(10,"10",(int a,String b) -> System.out.println(a+b ));
    }

    public static void m2(int x,M2 m2) {
        m2.test2(x);
    }

    public static void m22(int x,String y,M22 m22) {
        m22.test22(x,y);
    }

}

interface M2{
    void test2(int a);
}

interface M22{
    void test22(int a,String b);
}

3.5 无参有返回值

package com.qf.jdk.lambda;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 无参有返回值得lambda
 */
public class Demo4TestLambda {
    /**
     * 1 方法得有参数
     * 2 参数得是接口
     * 3 接口中只能有一个抽象方法
     */
    public static void main(String[] args) {
        // 匿名内部类
        m3(new M3( ) {
            @Override
            public int test3() {
                int a = 1;
                a++;
                return 200;
            }
        });

        // lambda
        // lambda 中有且只有一行语句时,return可以省略
        m3(() -> 302);
        m3(() -> {return 302;});
        // lambda中有多行语句,return不能省略
        m3(() -> {
            int a = 1;
            a++;
            return 302;
        });

    }


    public static void m3(M3 m3){
        int i = m3.test3( );
        System.out.println(i );
    }


}

interface M3 {
    int test3();
}

3.6 有参有返回值

设计一个方法m4,方法的参数列表是接口

该接口中有1个抽象方法,能接收两个int类型参数,返回值是String

要求,给m4方法传入lambda表达式,功能是将传入的两个参数拼接为String后返回

public class Demo5TestLambda {

    /**
     * 设计一个方法m4,方法的参数列表是接口
     * 该接口中有1个抽象方法,能接收两个int类型参数,返回值是String
     * 要求,给m4方法传入lambda表达式,功能是将传入的两个参数拼接为String后返回
     */
    public static void main(String[] args) {

        m4(10,20,(x,y) ->x+""+y);

    }


    public static void m4(int a,int b,M4 m4) {
        String str = m4.test4(a,b);
        System.out.println(str );
    }
}
interface M4{
    String test4(int a,int b);
}

3.7 练习

ArrayList 集合中的元素使用 Collections 工具类进行排序.

Collections.sort(list,compartor) 其中可以指定一个比较器,进行自定义排序

用lambda

package com.qf.jdk.lambda;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 实战
 */
public class Demo6TestLambda {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>( );
        list.add(5);
        list.add(5);
        list.add(3);
        list.add(2);
        list.add(1);
        list.add(4);

        for (Integer integer : list) {
            System.out.println(integer );
        }

        System.out.println("------" );
        // 集合工具类,sort()方法,默认对集合中元素进行升序
        // Collections.sort(list);
        //
        // for (Integer integer : list) {
        //     System.out.println(integer );
        // }

        // 重载的方法,可以传入一个比较器,进行自定义排序
        // 使用lambda 完成对list降序排序
        /**
         * 1 方法有参数
         * 2 参数是接口
         * 3 接口只有一个抽象方法
         * ---------------
         * lambda就是对接口的抽象方法重写
         */
        Collections.sort(list,(x,y) -> y-x);

        for (Integer integer : list) {
            System.out.println(integer );
        }
    }
}

四、函数式接口

接口中只有一个抽象方法时,该接口就是函数式接口.

为什么叫做函数式接口?因为这种接口,放在方法中档参数时,可以改造成lambda,进行运算.


Java提供了一个注解可以校验接口是否是函数式接口

@FunctionalInterface

Java中提供了几个特别常用的函数式接口

  • Supplier 供应,即返回一个数据
  • Consumer 消费,即给其传入数据做运算
  • Function 函数,传入2个参数,用于转换数据的
  • Predicate 判断,返回时boolean

4.1 Supplier

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
// 该接口用来返回一个数据,所以叫供应商
// 其实就是无参数有返回值的接口,用的时候就是无参有返回值的lambda

练习,设计方法,通过Supplier接口,获得字符串的长度

    public static void main(String[] args) {

        String str = "java";

        // 获得字符串长度
        getStringLength(() -> str.length());
        // 获得字符串首字母
        getStringLength(() -> (int) str.charAt(0));
        // 获得某个字符下标
        getStringLength(() -> str.indexOf('v'));
    }

    public static void getStringLength(Supplier<Integer> supplier){
        Integer length = supplier.get();
        System.out.println(length);
    }

4.2 Consumer

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     * 给传入一个值,对该值进行操作
     * @param t the input argument
     */
    void accept(T t);
}
// 其实就是有参数无返回值的接口,用的时候就是有参无返回值的lambda

练习:设计方法,传入字符串,将字符串全部转大写,后输出

    public static void main(String[] args) {

        String str = "java";
        // 这次使用一个字符串,将字符串变大写
        toUpperCase("java",s -> {
            String string = s.toUpperCase( );
            System.out.println("string = " + string);
        });

        // 这次是使用一个字符串,截取后缀
        toUpperCase("从入门到精通.txt",s -> System.out.println(s.substring(s.length() - 3) ));

    }

    public static void toUpperCase(String str, Consumer<String> consumer){
        consumer.accept(str);
    }

4.3 Function

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}
// 该接口用于,转换数据
// 其实就是有参数有返回值的接口,用的时候就是有参有返回值的lambda

练习,设计方法,将传入的字符串数字,转为整形数字

    public static void main(String[] args) {
        // 将传入的字符串变为数字返回
        change("1122",(string) -> Integer.parseInt(string));

        // 将传入的数字放大10倍后变为字符串返回
        change2(100,i -> String.valueOf(i * 10));

    }

    public static void change2(Integer i, Function<Integer,String> function) {
        String str = function.apply(i);
        System.out.println("str = " + str);
    }

    public static void change(String str, Function<String,Integer> function) {
        Integer num = function.apply(str);
        System.out.println("num = " + num);
    }

4.4 Predicate

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}
// 用于判断数据
// 其实就是有参数有返回值为boolean的接口,用的时候就是有参有返回值为boolean的lambda

设计方法,判断数据

    public static void main(String[] args) {
        // 判断人名,是否太长,大于3即认为太长
        isTrue("迪丽热巴",name -> name.length() > 3);

        // 判断年龄,年龄不能超过 0-150之间
        isTrue2(220,age -> age <= 150 && age >= 0);
    }

    public static void isTrue2(Integer age, Predicate<Integer> predicate){
        boolean test = predicate.test(age);
        System.out.println("test = " + test);
    }


    public static void isTrue(String name, Predicate<String> predicate){
        boolean test = predicate.test(name);
        System.out.println("test = " + test);
    }

作业

定义一个方法,传入一个字符串,输出字符串的长度
定义一个方法,传入一个数组,获取数组最大值
定义一个方法,返回100内最大质数
定义一个方法,传入一个数组,返回指定数组的和
定义一个方法,传入一个数,判断他是否是3的倍数

五、Stream流

Stream流,不要和之前学的IO流进行联想,他们之间没有关系.

IO流,数据像水流一样在传输

Stream流,数据像车间流水线,在一直往下走动,不是保存数据,也不纯粹的传输数据,而是像车间流水线一样,在处理数据.

Stream流可以让我们更快的处理数据.

分别演示之前处理数据,和使用Stream流来处理数据

package com.qf.jdk.stream;

import java.util.ArrayList;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 分别演示之前处理数据,和使用Stream流来处理数据
 */
public class Demo1 {

    public static void main(String[] args) {
        // 现有集合如下
        ArrayList<String> list = new ArrayList<>( );
        list.add("迪丽热巴-甲龙");
        list.add("马尔扎哈-鹏龙");
        list.add("杨顺博");
        list.add("刘路");
        list.add("古力娜扎-王莹莹");
        // show1();
        show2(list);
    }

    // 使用Stream来完成
    public static void show2(ArrayList<String> list) {
        list.stream().
                filter(name-> name.length()>2).
                filter(name -> name.contains("龙")).
                forEach(name -> System.out.println(name ));
    }

    // 未使用Stream流
    public static void show1(ArrayList<String> list) {
        // 条件1: 找到人名中长度大于2的
        // 条件2: 在1的基础上,再找名字里面包含"龙"的人名
        for (String name : list) {
            if (name.length() > 2) {
                if (name.contains("龙")) {
                    System.out.println("name = " + name);
                }
            }
        }
    }
}

5.1 获得流

Java提供了几种方式,可以让我们获得Stream流

  1. [集合创建流]Collection 接口的 stream()或 parallelStream()方法
  2. [自由值创建]静态的 Stream.of()、Stream.empty()方法
  3. [数组创建流]Arrays.stream(array)
  4. 静态的 Stream.generate()方法生成无限流,接受一个不包含引元的函数
  5. 静态的 Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数
  6. Pattern 接口的 splitAsStream(input)方法
  7. 静态的 Files.lines(path)、Files.lines(path, charSet)方法
  8. 静态的 Stream.concat()方法将两个流连接起来
package com.qf.jdk.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 获得流
 */
public class Demo2 {

    public static void main(String[] args) {
        // 现有集合如下
        ArrayList<String> list = new ArrayList<>( );
        list.add("迪丽热巴-甲龙");
        list.add("马尔扎哈-鹏龙");
        list.add("杨顺博");
        list.add("刘路");
        list.add("古力娜扎-王莹莹");

        // 1 通过集合获得流
        Stream<String> stream = list.stream( );
        // stream.forEach();

        // 2 通过数组创建流
        String[] address = {"郑州","驻马店","周口","商丘","濮阳"};
        Stream<String> stream1 = Arrays.stream(address);

        // 3 通过Stream的静态方法来完成
        Stream<Integer> stream2 = Stream.of(1, 2, 3, 4);
    }
}

5.2 流的操作

Stream流就是流式处理数据,流的操作有很多种

  • 获得流
  • 中间操作(真正处理数据的操作)
  • 终止操作(将操作完的结果返回)
操作 函数 说明
中间操作 filter(Predicate) 将结果为false的元素过滤掉
中间操作 map(Function) 转换元素的值,可以用方法引元或者lambda表达式
中间操作 limit(long n) 保留前n个元素
中间操作 skip(long n) 跳过前n个元素
中间操作 concat(Stream s1, Stream s2) 将两个流拼接起来
中间操作 flatMap(Function) 若元素是流,将流摊平为正常元素,再进行元素转换
中间操作 distinct() 剔除重复元素
中间操作 sorted() 将Comparable元素的流排序
中间操作 sorted(Comparator) 将流元素按Comparator排序
中间操作 peek(Consumer) 流不变,但会把每个元素传入fun执行,可以用作调试
终结操作 max(Comparator) 取最大值
终结操作 min(Comparator) 取最小值
终结操作 count() 统计元素数量
终结操作 findFirst() 获得流的第一个元素
终结操作 findAny() 返回任意元素
终结操作 anyMatch(Predicate) 任意元素匹配时返回true
终结操作 allMatch(Predicate) 所有元素匹配时返回true
终结操作 noneMatch(Predicate) 没有元素匹配时返回true
终结操作 reduce(Function) 从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数
终结操作 iterator() 迭代器迭代元素
终结操作 forEach(Consumer) lambda的方式迭代
终结操作 forEachOrdered(Consumer) 可以应用在并行流上以保持元素顺序

Stream流的操作注意事项

  1. 流的操作只能使用一次
  2. 使用中间操作,返回新的流
  3. 没有终止操作,就不会有结果,换句话说,没有终结操作,中间操作是 不会执行的
package com.qf.jdk.stream;

import java.util.ArrayList;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 流使用时注意事项
 */
public class Demo3 {

    public static void main(String[] args) {
        // 现有集合如下
        ArrayList<String> list = new ArrayList<>( );
        list.add("迪丽热巴-甲龙");
        list.add("马尔扎哈-鹏龙");
        list.add("杨顺博");
        list.add("刘路");
        list.add("古力娜扎-王莹莹");

        Stream<String> stream = list.stream( );

        // 第一次使用流
        // stream.forEach((e) -> System.out.println(e));
        // 第2次使用流,报错!! 只能用一次
        // stream.forEach((e) -> System.out.println(e));

        // 中间操作的方法,会返回新的流
        Stream<String> stream2 = stream.filter((name) -> name.length( ) > 2);
        Stream<String> stream3 = stream2.filter((name) -> name.contains("龙"));

        // 有终止操作,上面的中间操作才会执行
        stream3.forEach((name) -> System.out.println(name ));
    }
}


下面演示流的操作使用 - 中间操作

package com.qf.jdk.stream;

import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 操作流
 */
public class Demo4 {

    public static void main(String[] args) {
        // 1 获得流
        Stream<String> stream = Stream.of("11", "11","22","22", "33");
        Stream<String> stream2 = Stream.of("aa", "bb", "cc");
        // 2 limit(long n) 保留流里面的前几个
        // stream.limit(2).forEach(s -> System.out.println(s ));

        // 3 skip(long n) 跳过前几个
        // stream.skip(2).forEach(s -> System.out.println(s ));

        // 4 concat 拼接两个流为新的流
        // 该方法是Stream接口中的静态方法,直接通过接口名调用
        // Stream.concat(stream,stream2).forEach(s -> System.out.println(s ));

        // 5 distinct 将流中的数据去重
        // stream.distinct().forEach(s -> System.out.println(s ));

        // 6 sorted 排序,默认是升序
        Stream<Integer> stream3 = Stream.of(5,3,2,1,4);
        // stream3.sorted().forEach(s -> System.out.println(s ));

        stream3.sorted((o1,o2) -> o2 - o1).forEach(s -> System.out.println(s ));

    }

    private static void testMap() {
        // 1 获得流
        Stream<String> stream = Stream.of("11", "22", "33");

        // 2 流操作,map映射,传入元素,转换后再返回
        // 需求,将字符串数字,映射为整形数字返回
        // Stream integerStream = stream.map((str) -> Integer.parseInt(str));

        // 3 终止操作
        // integerStream.forEach((i) -> System.out.println(i));

        stream.map(str -> Integer.parseInt(str)).forEach(i -> System.out.println(i));
    }
}

下面演示流的操作使用 - 终止操作

package com.qf.jdk.stream;

import jdk.nashorn.internal.ir.IfNode;

import java.util.Iterator;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo5 {

    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(5, 3, 2, 1, 4);

        // 1 终止操作min,返回的是Optional类
        // Optional类中有个方法,get() ,可以获得其中的数据
        // min方法返回的是,排序后的第一个
        // Optional optional = stream.min((o1, o2) -> o1 - o2);
        // Integer min = optional.get( );
        // System.out.println(min );

        // Integer min = stream.min((o1, o2) -> o1 - o2).get( );

        // 2 count() 计数
        // System.out.println(stream.count( ));
        // long count = stream.filter(e -> e > 2).count( );
        // System.out.println(count );

        // 3 findFirst() 获得流里面第一个,返回Optional
        // System.out.println(stream.findFirst( ).get( ));

        // 4 anyMatch(Predicate)  任意元素匹配时返回true
        // 判断流里面的元素,任意一个都>3
        // 任意一个是,只要有一个就可以
        // System.out.println(stream.anyMatch(i -> i > 3));

        // 5 allMatch(Predicate)  全部元素匹配时返回true
        // System.out.println(stream.allMatch(i -> i > 3));

        // 6 reduce() 将元素归纳
        // 假设我们对一个集合中的值进行求和
        // System.out.println(stream.reduce(0, (sum, e) -> {
        //     System.out.println("sum = " + sum);
        //     System.out.println("e = " + e);
        //     return sum + e;
        // }));

        // 7 iterator()  迭代器迭代元素
        // Iterator iterator = stream.iterator( );
        // while (iterator.hasNext()) {
        //     Integer next = iterator.next( );
        //     System.out.println(next );
        // }
    }
}

5.3 流的收集

是将数组,集合等数据变成流,然后才进行操作

操作完,将数据再返回成数组和集合呢? --> 这就是收集流

将流收集到集合或数组中

  • collect() 收集到集合
  • toArray 收集到数组
package com.qf.jdk.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo6 {

    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(5, 5,3, 2, 1, 4,4);

        // 流中数据转成list集合
        // List list = stream.filter(i -> i > 3).collect(Collectors.toList( ));
        // System.out.println(list );

        // 流中数据转成set集合
        // Set set = stream.filter(i -> i > 3).collect(Collectors.toSet( ));
        // System.out.println(set );

        // 流可以转成数组
        // Object[] array = stream.toArray( );

        // 也可转成指定类型的数组
        Integer[] array = stream.toArray((length) -> new Integer[length]);
        System.out.println(Arrays.toString(array));
    }
}

六、新日期API

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。

在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:

  • 非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
  • 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  • 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
/*一些吐槽:
1.java.util.Date被设计为日期 + 时间的结合体。也就是说如果只需要日期,或者只需要单纯的时间,用Date是做不到的。
2. 年要减1900…  月从0-11 …
3.	Date是可变的,也就是说我把一个Date日期时间对象传给方法,方法内竟然还能更改
*/
@Test 
public void test() { 
    Date currDate = new Date(); 
    System.out.println("当前日期是①:" + currDate); 
    boolean holiday = isHoliday(currDate); 
    System.out.println("是否是假期:" + holiday); 
 
    System.out.println("当前日期是②:" + currDate); 
} 
 
/** 
 * 是否是假期 
 */ 
private static boolean isHoliday(Date date) { 
    // 架设等于这一天才是假期,否则不是 
    Date holiday = new Date(2021 - 1900, 10 - 1, 1); 
 
    if (date.getTime() == holiday.getTime()) { 
        return true; 
    } else { 
        // 模拟写代码时不注意,使坏 
        date.setTime(holiday.getTime()); 
        return true; 
    } 
}

日期

LocalDate

	@Test
	public void test02() {
		// ========== 获得日期 ==========
		// 获得当前日期
		LocalDate now = LocalDate.now();
		System.out.println(now);
		// 获得指定日期的时间
		LocalDate date = LocalDate.of(2020, 1, 1);
		System.out.println(date);
		
		// 获得年
		System.out.println(now.getYear());
		// 获得月
		System.out.println(now.getMonthValue());
		// 获得日
		System.out.println(now.getDayOfMonth());
		
		// ========== 设置日期 ==========
		// 设置之后返回的日期是一个新的日期对象,之前的日期并未更改
		// 设置年
		LocalDate withYear = now.withYear(1990);
		// 设置月
		LocalDate withMonth = now.withMonth(8);
		// 设置日
		LocalDate withDayOfMonth = now.withDayOfMonth(8);
		System.out.println(now);
		System.out.println(withYear);
		// 增加日期,返回新的日期对象
		// 增加的方法plusXxx()
		LocalDate plusYears = now.plusYears(2);
		
		// 减少日期
		// 减少的方法 minusXxx()
		LocalDate minusYears = now.minusYears(2);

	}

时间

LocalTime

	@Test
	public void test03() {
		// ========== 获得时间 ==========
		// 获得当前时间
		LocalTime now = LocalTime.now();
		System.out.println(now);
		// 获得指定时间
		LocalTime of1 = LocalTime.of(10, 10); // 时分
		LocalTime of2 = LocalTime.of(10, 10,10);// 时分秒
		LocalTime of3 = LocalTime.of(10, 10,10,10);// 时分秒纳秒
		System.out.println(of1);
		
		// 获得时,分,秒
		System.out.println(now.getHour());
		System.out.println(now.getMinute());
		System.out.println(now.getSecond());
		
		// ========== 设置时间 ==========
		// 设置时
		LocalTime hour = now.withHour(8);
		// 设置分
		LocalTime minute = now.withMinute(8);
		// 设置秒
		LocalTime second = now.withSecond(8);
		System.out.println(now);
		System.out.println(hour);
				
        // 增加时间,返回新的时间对象
		// 增加的方法plusXxx()
		LocalTime plus = now.plusHours(2);
		
		// 减少时间
		// 减少的方法 minusXxx()
		LocalTime minus = now.minusHours(2);
	}

日期时间

LocalDateTime

	@Test
	public void test04() {
		// ========== 获得日期时间 ==========
		// 获得当前时间
		LocalDateTime now = LocalDateTime.now();
		System.out.println(now);
		// 获得指定时间
		LocalDateTime of1 = LocalDateTime.of(1900, 1, 1, 10, 10); //年月日时分
		LocalDateTime of2 = LocalDateTime.of(2000, 10,10,8,8,8);// 年月日时分秒
		System.out.println(of1);
		
		// 获得年,月,日
		System.out.println(now.getYear());
		System.out.println(now.getMonthValue());
		System.out.println(now.getDayOfMonth());
		// 获得时,分,秒
		System.out.println(now.getHour());
		System.out.println(now.getMinute());
		System.out.println(now.getSecond());
		
		// ========== 设置日期时间 ==========
		// 设置时
		LocalDateTime hour = now.withHour(8);
		// 设置分
		LocalDateTime minute = now.withMinute(8);
		// 设置秒
		LocalDateTime second = now.withSecond(8);
		System.out.println(now);
		System.out.println(hour);

		// 增加时间,返回新的时间对象
		// 增加的方法plusXxx()
		LocalDateTime plus = now.plusHours(2);
		
		// 减少时间
		// 减少的方法 minusXxx()
		LocalDateTime minus = now.minusHours(2);

		System.out.println(now.isAfter(plus));
		System.out.println(now.isBefore(plus));
		System.out.println(now.isEqual(plus));
	}

你可能感兴趣的:(javaSE-学习笔记,学习,java,jvm)