文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java——JDK1.8新特性

2023-09-22 16:31

关注

目录

一、Lambda 表达式

(一)Lambda 表达式语法

(二)类型推断

二、函数式接口

(一)自定义函数式接口

(二)作为参数传递Lambda 表达式

(三)Java 内置四大核心函数式接口

三、方法引用

四、Stream API

(一)什么是Stream?

(二)Stream 的操作三个步骤

(三)创建流的四种方式

(四)Stream的中间操作

(五)Stream的终止操作

五、综合案例

六、新时间日期API

(一)使用LocalDate、LocalTime、LocalDateTime

(二)使用Instant时间戳

(三)Duration 和 Period

(四)日期的操纵

(五)解析与格式化

(六)时区的处理

(七)与传统日期处理的转换

七、接口中的默认方法与静态方法

八、其他新特性

(一)Optional 类

(二)重复注解与类型注解


一、Lambda 表达式

Lambda 是一个 匿名函数 ,我们可以把 Lambda表达式理解为是 一段可以传递的代码 (将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。 案例:从匿名内部类---》Lambda表达式
    // 原来的匿名内部类    @Test    public void test1() {        Comparator com = new Comparator() {            @Override            public int compare(Integer o1, Integer o2) {                return Integer.compare(o1, o2);            }        };        TreeSet ts = new TreeSet<>(com);    }    // Lambda表达式    @Test    public void test2() {        Comparator com = (o1, o2) -> Integer.compare(o1, o2);        TreeSet ts = new TreeSet<>(com);    }

(一)Lambda 表达式语法

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ -> ” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:

语法格式一:无参,无返回值,Lambda体只需一条语句

 语法格式二:Lambda需要一个参数

语法格式三:Lambda只需要一个参数时,参数的小括号可以省略 

语法格式四:Lambda需要两个参数,并且有返回值

语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略

 (二)类型推断

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的 “类型推断“

二、函数式接口

只包含一个抽象方法的接口,称为 函数式接口

(一)自定义函数式接口

(二)作为参数传递Lambda 表达式

作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接 收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口 的类型。

(三)Java 内置四大核心函数式接口

 

其他子接口(参数个数) 

public class TestLambda02 {        @Test    public void test04() {        List stringList = Arrays.asList("hello", "world","you");        List list = getStringList(stringList, (s) -> s.length() > 3);        list.forEach(System.out::println);    }    public List getStringList(List stringList, Predicate pre) {        List strings = new ArrayList<>();        for (String s : stringList) {            if(pre.test(s)) {                strings.add(s);            }        }        return strings;    }        @Test    public void test03() {        String string = getString("\t\t\t 帅哥好帅", (str) -> str.trim());        System.out.println(string);    }    public String getString(String str, Function func) {        return func.apply(str);    }        @Test    public void test02() {        int num = 10;        generator(num, () -> (int)(Math.random() * 100) + 1);    }    public void generator(int x, Supplier sup) {        List integerList = new ArrayList<>();        for(int i = 0; i < x; i ++) {            Integer integer = sup.get();            integerList.add(integer);        }        integerList.forEach(System.out::println);    }        @Test    public void test01() {        int num = 100;        consumer(num, x -> System.out.println("消费了" + num + "元"));    }    public void consumer(int num, Consumer com) {        com.accept(num);    }}

三、方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! 实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致! 方法引用:使用操作符 “ :: ” 将方法名和对象或类的名字分隔开来。 如下三种主要使用情况
public class TestMethodRef {    // 数组引用    @Test    public void test05() {        Function func = (x) -> new String[x];        String[] strings = func.apply(10);        System.out.println(strings.length);        Function func2 = String[]::new;        String[] strs = func2.apply(20);        System.out.println(strs.length);    }    // 构造器引用    @Test    public void test04() {        Supplier sup = () -> new Employee();        // 构造器引用的方式        Supplier sup2 = Employee::new;        Employee employee = sup2.get();        System.out.println(employee);                Function func = Employee::new;        Employee employee1 = func.apply(20);        System.out.println(employee1);    }    // 类::实例方法名    @Test    public void tes03() {        // 规则:若Lambda参数列表中的第一参数是实例方法的调用者,第二参数是实例方法的参数时,此时        //      可以通过 class::method        BiPredicate bp = (x, y) -> x.equals(y);        BiPredicate bp1 = String::equals;    }    // 对象::静态方法    @Test    public void  test02() {        Comparator com = (x, y) -> Integer.compare(x, y);        Comparator com1 = Integer::compare;    }    // 对象::实例方法    @Test    public void test01() {        PrintStream ps = System.out;        Consumer con = (x) -> System.out.println(x);        Consumer con2 = ps::println;    }}

 四、Stream API

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*) 。 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

(一)什么是Stream?

流(Stream) 到底是什么呢? 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,流讲的是计算!” 注意: ①Stream 自己不会存储元素。 ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。 ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

 (二)Stream 的操作三个步骤

        一个数据源(如:集合、数组),获取一个流         一个中间操作链,对数据源的数据进行处理         一个终止操作,执行中间操作链,并产生结果

(三)创建流的四种方式

方式一:Collection接口

Java8 中的 Collection 接口被扩展,提供了 两个获取流的方法 default Stream stream() : 返回一个顺序流 default Stream parallelStream() : 返回一个并行流

方式二:数组创建流

Java8 中的 Arrays 的静态方法 stream() 可 以获取数组流: static Stream stream(T[] array): 返回一个流 重载形式,能够处理对应基本类型的数组: public static IntStream stream(int[] array) public static LongStream stream(long[] array) public static DoubleStream stream(double[] array) 方式三:由值创建流 可以使用静态方法 Stream.of(), 通过显示值 创建一个流。它可以接收任意数量的参数。 public static Stream of(T... values) : 返回一个流 方式四:由函数创建流 可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。 迭代 public static Stream iterate(final T seed, final UnaryOperator f) 生成 public static Stream generate(Supplier s) :
public class testStream {    // 创建stream    @Test    public void test1() {        //1.可以通过Collection 系列集合提供的stream() or parallelStream()        List list = new ArrayList<>();        Stream stream1 = list.stream();        //2. 通过Arrays的静态方法stream()获取数组流        Employee[] emps = new Employee[2];        Stream stream2 = Arrays.stream(emps);        //3. 通过stream的静态方法of()        Stream stream3 = Stream.of(1, 2, 3);        //4. 创建无限流        // 迭代        Stream stream4 = Stream.iterate(0, (x) -> x + 2);        stream4.limit(10).forEach(System.out::println);        // 生成        Stream stream5 = Stream.generate(Math::random);        stream5.limit(10).forEach(System.out::println);    }}

 (四)Stream的中间操作

多个 中间操作 可以连接起来形成一个 流水线 ,除非流水线上触发终止操作,否则 中间操作不会执行任何的处理 !而在 终止操作时一次性全部处理,称为“惰性求值” 筛选与切片

 映射

排序

public class testStreamApi {    List empList = Arrays.asList(            new Employee("张三", 50, 7777.77),            new Employee("李四", 35, 8888.6),            new Employee("王五", 20, 999.55),            new Employee("赵六", 40, 1000.5),            new Employee("赵六", 40, 1000.5),            new Employee("赵六", 40, 1000.5));    // 中间操作        @Test    public void test06() {        List strs = Arrays.asList("aaa", "bbb", "ccc");        strs.stream()                .sorted()  // 按已经实现的comparator接口的排序规则进行排序称为自然排序                .forEach(System.out::println);        // 先按年龄排序,然后按姓名排序        empList.stream()                .sorted((x, y) -> {                    if(x.getAge().equals(y.getAge())) {                        return x.getName().compareTo(y.getName());                    }                    return x.getAge().compareTo(y.getAge());                })                .forEach(System.out::println);    }        @Test    public void test05() {        List stringList = Arrays.asList("aaa", "bbb", "ccc");        stringList.stream()                .map((str) -> str.toUpperCase())                .forEach(System.out::println);        System.out.println("---------------------------------");        // 获取员工的名字        empList.stream()                .distinct()                .map(Employee::getName)                .forEach(System.out::println);        System.out.println("---------------------------------");        // map实现将每个字符串转化为字符  复杂        Stream> streamStream = stringList.stream()                .map(testStreamApi::filterCharacter);        streamStream.forEach((sm) -> {            sm.forEach(System.out::println);        });        System.out.println("---------------------------------");        // flatMap实现将每个字符串转化为字符 简单        Stream stream = stringList.stream()                .flatMap(testStreamApi::filterCharacter);        stream.forEach(System.out::println);    }    public static Stream filterCharacter(String str) {        List list = new ArrayList<>();        for(Character ch : str.toCharArray()) {            list.add(ch);        }        return list.stream();    }        @Test    public void test04() {        empList.stream()                .filter((e) -> e.getAge() > 30)                .skip(2)                .distinct() // 这里是根据hashCode和equals,所以employee需要重写hashCode和equals                .forEach(System.out::println);    }    @Test    public void test03() {        empList.stream()                .filter((e) -> e.getAge() > 30)                .limit(2)                .forEach(System.out::println);    }    // 内部迭代:即stream内部帮我们迭代    @Test    public void test01() {        // 中间操作        Stream stream = empList.stream()                .filter((e) -> e.getAge() > 30);        // 终止操作:一次性执行全部内容,即“惰性求值”        stream.forEach(System.out::println);    }    // 外部迭代    @Test    public void test02() {        Iterator iterator = empList.iterator();        while(iterator.hasNext()) {            Employee employee = iterator.next();            if(employee.getAge() > 30) {                System.out.println(employee);            }        }    }}

 (五)Stream的终止操作

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

public class testStreamApi2 {    List empList = Arrays.asList(            new Employee("张三", 50, 7777.77, Employee.Status.FREE),            new Employee("李四", 35, 8888.6, Employee.Status.BUSY),            new Employee("王五", 20, 999.55, Employee.Status.VOCATION),            new Employee("赵六", 40, 1000.5, Employee.Status.BUSY),            new Employee("赵六", 40, 1000.5, Employee.Status.FREE),            new Employee("赵六", 40, 1000.5, Employee.Status.VOCATION));        // 其他    @Test    public void test09() {        DoubleSummaryStatistics ssd = empList.stream()                .collect(Collectors.summarizingDouble(Employee::getSalary));        System.out.println(ssd.getAverage());        System.out.println(ssd.getMax());        System.out.println(ssd.getMin());        String str = empList.stream()                .map(Employee::getName)                .collect(Collectors.joining(",", "===", "==="));        System.out.println(str);    }    // 分区    @Test    public void test08() {        // 分成true和false两个区        Map> map = empList.stream()                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 5000));        System.out.println(map);    }    // 多级分组    @Test    public void test07() {        Map>> map = empList.stream()                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {                    if (e.getAge() < 30) {                        return "青年";                    } else if (e.getAge() < 50) {                        return "中年";                    } else {                        return "老年";                    }                })));        System.out.println(map);    }    // 分组    @Test    public void test06() {        Map> map = empList.stream()                .collect(Collectors.groupingBy(Employee::getStatus));        System.out.println(map);    }    @Test    public void test05() {        Long size = empList.stream()                .collect(Collectors.counting());        System.out.println(size);        Double avg = empList.stream()                .collect(Collectors.averagingDouble(Employee::getSalary));        System.out.println(avg);        Double sum = empList.stream().collect(Collectors.summingDouble(Employee::getSalary));        System.out.println(sum);        Optional max = empList.stream()                .map(Employee::getSalary)                .collect(Collectors.maxBy(Double::compareTo));        System.out.println(max.get());        Optional min = empList.stream()                .collect(Collectors.minBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));        System.out.println(min.get());    }    @Test    public void test04() {        List list1 = empList.stream()                .map(Employee::getName)                .collect(Collectors.toList());        list1.forEach(System.out::println);        System.out.println("------------------------");        Set set = empList.stream()                .map(Employee::getName)                .collect(Collectors.toSet());        set.forEach(System.out::println);        System.out.println("------------------------");        LinkedHashSet hashSet = empList.stream()                .map(Employee::getName)                .collect(Collectors.toCollection(LinkedHashSet::new));        hashSet.forEach(System.out::println);    }        @Test    public void test03() {        List list = Arrays.asList(1, 2, 3);        Integer sum1 = list.stream()                .reduce(1, (x, y) -> x + y);        System.out.println(sum1);        Optional sum2 = empList.stream()                .map(Employee::getSalary)                .reduce(Double::sum);        System.out.println(sum2.get());    }        @Test    public void test02() {        // 数量        long count = empList.stream()                .count();        System.out.println(count);        // 最大值        Optional max = empList.stream()                .max((x, y) -> Double.compare(x.getSalary(), y.getSalary()));        System.out.println(max.get().getSalary());        // 最小值        Optional min = empList.stream()                .map(Employee::getSalary)                .min(Double::compareTo);        System.out.println(min.get());    }    @Test    public void test01() {        boolean b1 = empList.stream()                .allMatch((e) -> e.getStatus().equals(Employee.Status.FREE));        System.out.println(b1);        boolean b2 = empList.stream()                .anyMatch((e) -> e.getStatus().equals(Employee.Status.FREE));        System.out.println(b2);        boolean b3 = empList.stream()                .noneMatch((e) -> e.getStatus().equals(Employee.Status.FREE));        System.out.println(b3);        // 返回的值有可能为空所以封装到了Optional        Optional op1 = empList.stream()                .sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary()))                .findFirst();        System.out.println(op1.get());        Optional op2 = empList.stream()                .sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary()))                .findAny();        System.out.println(op2.get());    }}

 案例:

public class testStreamApi3 {        @Test    public void test() {        Integer[] num = new Integer[]{1, 2, 3, 4, 5};        Stream stream = Arrays.stream(num);        stream.map(x -> x*x).forEach(System.out::println);    }    List empList = Arrays.asList(            new Employee("张三", 50, 7777.77),            new Employee("李四", 35, 8888.6),            new Employee("王五", 20, 999.55),            new Employee("赵六", 40, 1000.5),            new Employee("赵六", 40, 1000.5),            new Employee("赵六", 40, 1000.5));        @Test    public void test2() {        Optional sum = empList.stream()                .map(e -> 1)                .reduce(Integer::sum);        System.out.println(sum.get());    }}

 五、综合案例

public interface MyPredicate {    public boolean test(Employee employee);}====================================================================    List empList = Arrays.asList(        new Employee("张三", 50, 7777.77),        new Employee("李四", 35, 8888.6),        new Employee("王五", 20, 999.55),        new Employee("赵六", 40, 1000.5)    );    // 需求:获取当前公司中员工年龄大于35的员工    @Test    public void test3() {        List employees = filterList(empList);        for (Employee employee : employees) {            System.out.println(employee);        }        System.out.println("---------------------------------");        employees = filterListBySalary(empList);        for (Employee employee : employees) {            System.out.println(employee);        }    }    public List filterList(List empList) {        List emps = new ArrayList<>();        for (Employee emp : empList) {            if(emp.getAge() > 35) {                emps.add(emp);            }        }        return emps;    }    // 需求:获取当前公司中员工工资大于4000的员工    public List filterListBySalary(List empList) {        List emps = new ArrayList<>();        for (Employee emp : empList) {            if(emp.getSalary() > 4000) {                emps.add(emp);            }        }        return emps;    }    // 优化方式一:策略设计模式    @Test    public void test4() {        List employees                = filterList(empList, new filterEmployeeByAge());        for (Employee employee : employees) {            System.out.println(employee);        }        System.out.println("--------------------------------");        employees                = filterList(empList, new filterEmployeeBySalary());        for (Employee employee : employees) {            System.out.println(employee);        }    }    public List filterList(List empList, MyPredicate pre) {        List emps = new ArrayList<>();        for (Employee emp : empList) {            if(pre.test(emp)) {                emps.add(emp);            }        }        return emps;    }    // 优化方式二:匿名内部类    @Test    public void test5() {        List emps = filterList(empList, new MyPredicate() {            @Override            public boolean test(Employee employee) {                return employee.getSalary() > 4000;            }        });        emps.forEach(System.out::println);    }    // 优化方式三:Lambda表达式    @Test    public void test6() {        List employees = filterList(empList, e -> e.getSalary() > 4000);        employees.forEach(System.out::println);    }    // 优化方式四:streamApi    @Test    public void test7() {        empList.stream()                .filter(e -> e.getSalary() > 4000)                .limit(1)                .forEach(System.out::println);        System.out.println("-----------------------");        empList.stream()                .map(Employee::getName)                .forEach(System.out::println);    }

六、新时间日期API

原本的时间相关的类存在线程安全问题

public class testSimpleDateFormat {    public static void main(String[] args) throws ExecutionException, InterruptedException {        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");        Callable task = new Callable() {            @Override            public Date call() throws Exception {                return sdf.parse("20230518");            }        };        ExecutorService pool = Executors.newFixedThreadPool(10);        List> results = new ArrayList<>();        for(int i = 0; i < 10; i ++) {            results.add(pool.submit(task));        }        for(Future future:results) {            System.out.println(future.get());        }        pool.shutdown();    }}

以前的方式,加锁,这里使用ThreadLocal

public class DateFormatThreadLocal {    private static final ThreadLocal df = new ThreadLocal(){            protected DateFormat initialValue() {                return new SimpleDateFormat("yyyyMMdd");            }    };    public static Date convert(String source) throws ParseException {        return df.get().parse(source);    }}=========================================================================public class testSimpleDateFormat {    public static void main(String[] args) throws ExecutionException, InterruptedException {//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");        Callable task = new Callable() {            @Override            public Date call() throws Exception {//                return sdf.parse("20230518");                return DateFormatThreadLocal.convert("20230518");            }        };        ExecutorService pool = Executors.newFixedThreadPool(10);        List> results = new ArrayList<>();        for(int i = 0; i < 10; i ++) {            results.add(pool.submit(task));        }        for(Future future:results) {            System.out.println(future.get());        }        pool.shutdown();    }}

 jdk1.8的时间类

public class testSimpleDateFormat {    public static void main(String[] args) throws ExecutionException, InterruptedException {        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");        Callable task = new Callable() {            @Override            public LocalDate call() throws Exception {                return LocalDate.parse("20230518", dtf);            }        };        ExecutorService pool = Executors.newFixedThreadPool(10);        List> results = new ArrayList<>();        for(int i = 0; i < 10; i ++) {            results.add(pool.submit(task));        }        for(Future future:results) {            System.out.println(future.get());        }        pool.shutdown();    }}

(一)使用LocalDateLocalTimeLocalDateTime

LocalDate LocalTime LocalDateTime 类的实例是 不可变的对象 ,分别表示使用 ISO-8601 历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

 

(二)使用Instant时间戳

用于“时间戳”的运算。它是以 Unix 元年 ( 传统的设定为UTC 时区 1970 1 1 日午夜时分 ) 开始所经历的描述进行运算

(三)Duration Period

Duration: 用于计算两个“时间”间隔 Period: 用于计算两个“日期”间隔

(四)日期的操纵

TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。 TemporalAdjuster s : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。

(五)解析与格式化

java.time.format.DateTimeFormatter 类:该类提供了三种 格式化方法: 预定义的标准格式 语言环境相关的格式 自定义的格式

(六)时区的处理

Java8 中加入了对时区的支持,带时区的时间为分别为: ZonedDate ZonedTime ZonedDateTime 其中每个时区都对应着 ID ,地区 ID 都为 “{区域 }/{ 城市 } ”的格式 例如 : Asia/Shanghai ZoneId :该类中包含了所有的时区信息         getAvailableZoneIds() : 可以获取所有时区时区信息         of(id) : 用指定的时区信息获取 ZoneId 对象

(七)与传统日期处理的转换

public class testLocalDateTime {    // ZonedDate/ZonedTime/ZonedDateTime 时区相关的    @Test    public void test8() {        // 获得的是指定时区的当前时间        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));        System.out.println(ldt);        LocalDateTime ldt2 = LocalDateTime.now();        ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Shanghai"));        // 输出2023-05-18T22:01:45.684+08:00[Asia/Shanghai]        // +08:00 是距离UTC的时间差        System.out.println(zdt);    }    @Test    public void test7() {        // 获取支持的时区        Set set = ZoneId.getAvailableZoneIds();        set.forEach(System.out::println);    }    // DateTimeFormatter : 格式化时间/日期    @Test    public void test6() {        DateTimeFormatter dtf1 = DateTimeFormatter.ISO_DATE;        LocalDateTime ldt1 = LocalDateTime.now();        System.out.println(ldt1.format(dtf1));        System.out.println("-------------------------------");        // 格式化        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");        String time = ldt1.format(dtf2);        System.out.println(time);        // 再格式化回去        LocalDateTime ldt2 = ldt1.parse(time, dtf2);        System.out.println(ldt2);    }    // TemporalAdjuster: 时间矫正器    @Test    public void test5() {        LocalDateTime ldt1 = LocalDateTime.now();        System.out.println(ldt1);        // 直接设置日期为哪一天,不太方便求下一个周几等的操作        LocalDateTime ldt2 = ldt1.withDayOfMonth(10);        System.out.println(ldt2);        // 求下一个星期日        LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));        System.out.println(ldt3);        //自定义:下一个工作日        LocalDateTime ldt5 = ldt1.with((l) -> {            LocalDateTime ldt4 = (LocalDateTime)l;            DayOfWeek dayOfWeek = ldt4.getDayOfWeek();            if(dayOfWeek.equals(DayOfWeek.FRIDAY)) {                return ldt4.plusDays(3);            } else if(dayOfWeek.equals(DayOfWeek.SATURDAY)) {                return ldt4.plusDays(2);            } else {                return ldt4.plusDays(1);            }        });        System.out.println(ldt5);    }    // 3、 Duration: 计算两个“时间”之间的间隔    //     Period: 计算两个“日期”之间的间隔    @Test    public void test4() {        LocalDate l1 = LocalDate.of(2022, 5, 17);        LocalDate l2 = LocalDate.now();        Period period = Period.between(l1, l2);        System.out.println(period);        System.out.println(period.getYears());        System.out.println(period.getMonths());        System.out.println(period.getDays());    }    @Test    public void test3() throws InterruptedException {        Instant i1 = Instant.now();        Thread.sleep(1000);        Instant i2 = Instant.now();        System.out.println(Duration.between(i1, i2));        System.out.println("----------------------------");        LocalTime l1 = LocalTime.now();        Thread.sleep(1000);        LocalTime l2 = LocalTime.now();        System.out.println(Duration.between(l1, l2));    }    // 2、Instant :时间戳(以Unix元年:1970年1月1日00:00:00到某个时间之间的毫秒数)    @Test    public void test2() {        Instant i1 = Instant.now(); // 默认获取UTC时区        System.out.println(i1);        // 与中国相差八个时区,可设置偏移        OffsetDateTime time = i1.atOffset(ZoneOffset.ofHours(8));        System.out.println(time);        // 从 1970-现在 的秒数        long second = i1.getEpochSecond();        System.out.println(second);        // 从元年开始计算,这里是+60s        Instant i2 = Instant.ofEpochSecond(60);        System.out.println(i2);    }    // 1、LocalDate LocalTime LocalDateTime(前两个的结合体)    // 一个会用另外两个也差不多了    @Test    public void test1() {        // 返回当前年月日时分秒毫秒        LocalDateTime ldt1 = LocalDateTime.now();        System.out.println(ldt1);        // 构造日期        LocalDateTime ldt2 = LocalDateTime.of(2023, 5, 18, 20, 2, 20);        System.out.println(ldt2);        // 加年数        LocalDateTime ldt3 = ldt1.plusYears(2);        System.out.println(ldt3);        // 减年数        LocalDateTime ldt4 = ldt1.minusYears(2);        System.out.println(ldt4);        // 取详细信息        System.out.println(ldt1.getYear());        System.out.println(ldt1.getMonthValue());        System.out.println(ldt1.getDayOfMonth());        System.out.println(ldt1.getHour());        System.out.println(ldt1.getMinute());        System.out.println(ldt1.getNano());    }}

 七、接口中的默认方法与静态方法

Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法” ,默认方法使用 default 关键字修饰。 接口默认方法的”类优先”原则 若一个接口中定义了一个默认方法,而另外一个父类或接口中 又定义了一个同名的方法时 选择父类中的方法。如果一个父类提供了具体的实现,那么 接口中具有相同名称和参数的默认方法会被忽略。 接口冲突。如果一个父接口提供一个默认方法,而另一个接 口也提供了一个具有相同名称和参数列表的方法(不管方法 是否是默认方法),那么必须覆盖该方法来解决冲突 Java8 中,接口中允许添加静态方法。
public class MyClass {    public String getName() {        return "father";    }}===========================================================================public interface MyFun {    default String getName() {        return "hahaha";    }}===========================================================================public interface MyInterface {    default String getName() {        return "heiheihei";    }}===========================================================================public class SubClass extends MyClass implements MyFun, MyInterface {    // 两个接口中都有同名函数时,需要实现方法指定执行哪一个接口中的函数// 当父类中也有同名函数而子类中没有时,默认调用父类函数,忽略接口中的默认函数}===========================================================================public class testDefault {    public static void main(String[] args) {        SubClass subClass = new SubClass();        System.out.println(subClass.getName());    }}

public class SubClass extends MyClass implements MyFun, MyInterface {    // 两个接口中都有同名函数时,需要实现方法指定执行哪一个接口中的函数// 当父类中也有同名函数而子类中没有时,默认调用父类函数,忽略接口中的默认函数    @Override    public String getName() {        return MyInterface.super.getName();    }}

public interface MyInterface {    default String getName() {        return "heiheihei";    }    public static void show() {        System.out.println("展示");    }}==================================================public class testDefault {    public static void main(String[] args) {        SubClass subClass = new SubClass();        System.out.println(subClass.getName());        // 调用接口中的静态方法        MyInterface.show();    }}

八、其他新特性

(一)Optional

Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。 常用方法:
public class testOptional {        // 为什么说它方便了空指针异常的调试,因为这里出现空值会报错NoSuchElementException    @Test    public void test6() {        Optional optional = Optional.ofNullable(new Employee("张三", 18, 50000.0, Employee.Status.BUSY));//        Optional name = optional.map((e) -> optional.get().getName());//        System.out.println(name.get());        Optional name = optional.flatMap(e -> Optional.of(e.getName()));        System.out.println(name.get());    }    @Test    public void test5() {        Optional optional = Optional.ofNullable(null);        // 如果optional为空,那么返回传进去的默认参数,否则返回optional的参数        Employee employee1 = optional.orElse(new Employee());        System.out.println(employee1);        // 使用供给型函数式接口,如果optional为空,那么返回传进去的默认参数,否则返回optional的参数        Employee employee2 = optional.orElseGet(Employee::new);        System.out.println(employee2);    }    @Test    public void test4() {        Optional optional = Optional.ofNullable(null);//        System.out.println(optional.get()); // 报错NoSuchElementException        // 安全的做法,判断是否包含值        if(optional.isPresent()) {            System.out.println(optional.get());        }    }    @Test    public void test3() {        Optional optional = Optional.empty();        System.out.println(optional.get()); // 报错NoSuchElementException    }    @Test    public void test2() {        Optional optional = Optional.of(null); // 报错NullPointerException    }    @Test    public void test1() {        Optional optional = Optional.of(new Employee());        System.out.println(optional.get());    }}

(二)重复注解与类型注解

Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。
@Repeatable(MyAnnotaions.class) // 指明容器类@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotaion {    String value() default "atguigu";}===============================================================================@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotaions {    MyAnnotaion[] value();}===============================================================================public class TestAnnotaion {    @Test    public void test1() throws Exception {        Class aClass = TestAnnotaion.class;        Method method =                aClass.getMethod("show");        MyAnnotaion[] annotations = method.getAnnotationsByType(MyAnnotaion.class);        for(MyAnnotaion mya: annotations) {            System.out.println(mya);        }    }    @MyAnnotaion("world")    @MyAnnotaion("hello")    public void show(@MyAnnotaion("abc") String abs) {    }}

来源地址:https://blog.csdn.net/m0_62946761/article/details/130753016

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯