JDK8的新特性

一、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<Integer> 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<Integer> 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<Integer> 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<Integer> list = stream.filter(i -> i > 3).collect(Collectors.toList( ));
        // System.out.println(list );

        // 流中数据转成set集合
        // Set<Integer> 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));
	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二手Java程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值