【Java】全面理解Java8特性

目录

一、Java8中Interface接口

二、lambda表达式

语法格式

[三、函数式接口Functional Interface](#三、函数式接口Functional Interface)

[1. 作用](#1. 作用)

[2. 内置函数式接(Built-in Functional Interfaces)](#2. 内置函数式接(Built-in Functional Interfaces))

Predicate接口

Function

Comparator

四、Stream

[1. Filter 过滤](#1. Filter 过滤)

[2. Sorted 排序](#2. Sorted 排序)

[3. Map 映射](#3. Map 映射)

[4. Match 匹配](#4. Match 匹配)

[5. Collect收集](#5. Collect收集)

[6. Statistics 统计](#6. Statistics 统计)

[7. 函数式接口总结](#7. 函数式接口总结)

五、日期时间

[1. 格式化](#1. 格式化)

[2. 字符串转日期格式](#2. 字符串转日期格式)

[3. 日期计算](#3. 日期计算)

[4. 获取指定日期](#4. 获取指定日期)


一、Java8中Interface接口

Java8 中,接口中除了抽象方法外,还可以定义default默认方法 和 static 静态方法

default修饰的默认方法,属于实例方法,可以被实现类调用或重写。

调用:实现类必须 implements 接口,才能调用该接口的 default 默认方法。

重写 :实现类 implements不同接口时,接口中存在相同签名的方法(名称、参数、类型完全一致),则实现类必须重写该方法明确方法定义;

static 修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用 interface 接口名称调用。

二、lambda表达式

Lambda表达式本质 是一个匿名函数 ,用于把函数作为参数,传入方法中,实现函数式编程风格。

使用 Lambda表达式可以使代码变的更加简洁紧凑。

语法格式

(parameters)->expression(parameters)->{statements;}

    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Arrays.asList("s","sjv","safa","safth"));

        // Comparator接口的匿名实现方式(传统)
//        list.sort(new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o1.length()-o2.length();
//            }
//        });

        // lambda表达式的语法规则:(参数) -> {方法实现逻辑}
        // 使用lambda表达式,@FunctionalInterface接口,只有一个抽象方法(无方法体)
        // 通过lambda表达式实现Comparator接口
        list.sort((s1, s2) -> {
                        return s1.length()-s2.length();
                    });


        // 通过lambda表达式实现Consumer接口
        list.forEach((str)->{
            System.out.println(str.toUpperCase());
        });

        System.out.println(list);
    }

三、函数式接口Functional Interface

只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用 @FunctionalInterface 接

口定义,强化语义规范。

函数式接口,也被称为SAM接口(Single Abstract Method Interfaces)。

1. 作用

基于函数式接口,可以使用Lambda 表达式进行实现,实现函数式编程

2. 内置函数式接(Built-in Functional Interfaces)

在 Java 8中专门有一个包放函数式接口 java.util.function ,该包下的所有接口都有 @FunctionalInterface 注解,提供函数式编程方式。

Predicate接口

Predicate 接口是只有一个参数的返回布尔类型值的断言型 接口。该接口包含多种默认方法来将Predicate 组合成其他复杂的逻辑 (比如:与 and,或or,非negate)。

    public static void main(String[] args) {
//        Predicate predicate = new Predicate() {
//            @Override
//            public boolean test(Object o) {
//                return false;
//            }
//        };
        List<String> arrayList = new ArrayList<>(Arrays.asList("Basic","QBasic","c","c++","PowerBuilder","go"));

        // 查找名称小于3个字符的元素
        Predicate<String> predicate1 = (lang)-> {
            if (lang.length()<=3) {
                return true;
            }
            return false;
        };

        // 查询前缀以"b"或"c"开头的元素
        Predicate<String> predicate2 = (lang)->{
            if (lang.toLowerCase().startsWith("b")||lang.toLowerCase().startsWith("c")){
                return true;
            }
            return false;
        };

        // 条件组合:形成"与" 或 "或"逻辑关系
        Predicate<String> predicate3 = predicate1.and(predicate2);
        Predicate<String> predicate4 = predicate1.or(predicate2);

        // "非"逻辑 (取反)
        Predicate<String> predicate5 = predicate1.negate();  // >3

        arrayList.forEach((lang)->{
            if (predicate1.test(lang)){
                System.out.println(lang);
            }
        });

    }
Function

Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接 在一起(compose,andThen)。

    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Arrays.asList("Basic", "QBasic", "c", "c++", "PowerBuilder", "go"));

        // Function<参数类型,返回值类型>
        // 转换成大写字母形式
        Function<String, String> fun1 = (lang) -> {
            lang = lang.toUpperCase();
            return lang;
        };

        // 加上【】
        Function<String, String> fun2 = (lang) -> {
            lang = String.format("【%s】", lang);
            return lang;
        };

        // 组合
        Function<String, String> fun3 = fun1.andThen(fun2);  //先fun1,后fun2
        Function<String,String> fun4 = fun1.compose(fun2);

        list.forEach((lang) -> {
            String ret = fun3.apply(lang);
            System.out.println(ret);
        });
    }
Comparator

比较器接口,用于比较指定元素值的大小。 Java 8版本中,添加了多个新的 default 方法,用于比较器合并反转等操作。

    public static void main(String[] args) {
        List<String> list = Arrays.asList("Basic", "QBasic", "c", "c++", "PowerBuilder", "to","go");

        Comparator<String> comparator1 = (lang1, lang2) -> {
            int ret = lang1.compareTo(lang2);
            if (ret ==0){
                return lang1.length()-lang2.length();
            }
            return ret;
        };

        Comparator<String> comparable2 = comparator1.reversed();  // 反转

        list.sort(comparable2);

        list.forEach((lang)->{
            System.out.println(lang);
        });

    }

四、Stream

java.util.Stream表示能应用在一组元素上一次执行的操作序列。

Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回 stream 本身,可以连续完成多个操作。

1. Filter 过滤

过滤通过一个 predicate 接口来过滤并只保留符合条件的元素,该操作属于中间操作 。所以过滤后的结果,可以继续进行其它 stream操作(例如forEach,forEach需要一个函数来对过滤后的元素依次执行。 forEach 是一个最终操作)。

    public static void main(String[] args) {
        Stream<String> stream = Stream.of("Basic", "QBasic", "c", "c++", "PowerBuilder", "go", "BuilderPower");

        // 过滤所有小写字母内容的元素,并排序
        stream.filter((lang) -> {
            for (int i = 0; i < lang.length(); i++) {
                char c = lang.charAt(i);
                if (c > 'A' && c < 'Z') {
                    return true;
                }
            }
            return false;
        }).sorted((c1, c2) -> {
            if (c1.length() == c2.length()) {
                return c1.compareTo(c2);
            } else {
                return c1.length() - c2.length();
            }
        }).forEach((lang) -> {
            System.out.println(lang);
        });
    }

2. Sorted 排序

排序 是一个 中间操作,返回的是排序好后的Stream 。(不影响原数据)

    public static void main(String[] args) {
        Stream<String> stream = Stream.of("Basic", "QBasic", "c", "c++", "PowerBuilder", "go", "BuilderPower");

        // 过滤所有小写字母内容的元素,并排序
        stream.filter((lang) -> {
            for (int i = 0; i < lang.length(); i++) {
                char c = lang.charAt(i);
                if (c > 'A' && c < 'Z') {
                    return true;
                }
            }
            return false;
        }).sorted((c1, c2) -> {
            if (c1.length() == c2.length()) {
                return c1.compareTo(c2);
            } else {
                return c1.length() - c2.length();
            }
        }).forEach((lang) -> {
            System.out.println(lang);
        });
    }

3. Map 映射

映射 是一个中间操作,会将元素根据指定的 Function 接口来依次将元素转成另外的对象。

    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50, 60);

        // 映射:对每一个元素进行一次处理
        stream.map((n) -> {
            return n + 1;
        }).forEach((n) -> {
            System.out.println(n);
        });

        List<String> stringList = Arrays.asList("afa", "asf", "afsa");

        //转换字符串为大写,降序后输出
        stringList.stream().map((item) -> {
            return item.toUpperCase();
        }).sorted((s1, s2) -> {
            return s1.compareTo(s2);
        }).forEach((item) -> {
            System.out.println(item);
        });
    }

4. Match 匹配

Stream 提供了多种匹配操作,允许检测指定的 Predicate 是否匹配整个 Stream 。所有的匹配 操作都是 最终操作 ,并返回一个boolean 类型的值。

    public static void main(String[] args) {

        List<String> stringList = Arrays.asList("gds","asfa","das");

        // allMatch:所有元素是否匹配
        boolean bool1 = stringList.stream().allMatch((item) -> {
            return item.length() == 3;
        });
        System.out.println(bool1);

        // anyMatch:任意元素是否匹配
        boolean bool2 = stringList.stream().anyMatch((item) -> {
            return item.length() == 3;
        });
        System.out.println(bool2);

    }

5. Collect收集

收集 是一个 最终操作,返回 stream 中元素集合,返回值类型是集合(List、set、Map)或 字符串。

    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("1556","5612","8489");

        //将Stream流中的每个元素进行mapping映射操作后,然后收集至一个List集合
        //Collectors.mapping
        List<Integer> numberInt = stringList.stream().collect(Collectors.mapping(s -> Integer.parseInt(s) * 10, Collectors.toList()));
        System.out.println(numberInt);


        // 分组操作
        // Collectors.groupingBy
        // 按照元素的字符长度进行分组
        Stream<String> stream = Stream.of("Basic", "QBasic", "c", "c++", "PowerBuilder", "go","BuilderPower");
        Map<Integer, List<String>> resultMapGroup1 = stream.collect(Collectors.groupingBy(s -> s.length()));
        resultMapGroup1.forEach((k,v)->{
            System.out.println(k+":"+v);
        });
//        stream.collect(Collectors.groupingBy((s->s.length()))).forEach((k,v)->{
//            System.out.println(k+":"+v);
//        });

        // 按照元素的首字母进行分组
        stream = Stream.of("Basic", "QBasic", "c", "c++", "PowerBuilder", "go","BuilderPower");
        stream.collect(Collectors.groupingBy(s->s.charAt(0))).forEach((k,v)->{
            System.out.println(k+":"+v);
        });
    }

    public static void main(String[] args) {
        Stream<String> stream = Stream.of("Basic", "QBasic", "c", "c++", "PowerBuilder", "go","BuilderPower");

        // 分区操作(只有true和false)
        stream.collect(Collectors.partitioningBy(s->s.length()>3)).forEach((k,v)->{
            System.out.println(k+":"+v);
        });
    }

6. Statistics 统计

统计 是一个最终操作,返回 Stream中元素的各类统计信息,返回值类型是 XXXConsumer。

    public static void main(String[] args) {
        //统计操作
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        // Stream ===> IntStream
        IntStream intStream = list.stream().mapToInt(s -> s*10);
        IntSummaryStatistics statisticsResult = intStream.summaryStatistics();

        // 获取统计结果
        System.out.println("最大值:"+statisticsResult.getMax());
        System.out.println("最小值:"+statisticsResult.getMin());
        System.out.println("平均值:"+statisticsResult.getAverage());
        System.out.println("累加和:"+statisticsResult.getSum());
    }

7. 函数式接口总结

a. Predicate、Function、Consumer、Comparator

b. 通过链式编程,使得它可以方便地对数据进行链式处理。

c. 方法参数都是函数式接口类型

d. 一个stream 只能操作一次,操作完就关闭了,继续使用这个 stream会报错。Stream不保存数据,不改变数据源。

五、日期时间

  • LocalDateTime //日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
  • LocalDate //日期 format: yyyy-MM-dd
  • LocalTime //时间 format: HH:mm:ss

1. 格式化

    public static void main(String[] args) {
        // 日期格式化
        // 默认格式: yyyy-MM-dd
        LocalDate date = LocalDate.now();
        System.out.println(String.format("Date Format:%s",date));

        // 默认格式:HH:mm:ss
        LocalTime time =LocalTime.now().withNano(0);
        System.out.println(String.format("Time Format:%s",time));

        LocalDateTime dateTime = LocalDateTime.now();

        // 自定义格式:yyyy-MM-dd HH:mm:ss
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        String dateTimeStr = dateTime.format(dateTimeFormatter);
        System.out.println(String.format("DateTime Format:%s",dateTimeStr));
    }

2. 字符串转日期格式

    public static void main(String[] args) {
        // 字符串格式的日期内容,转换为LocalDate等之类的日期对象

        // 按照指定的日期的时间域值进行转换
        LocalDate date1 = LocalDate.of(2024,9,11);
        System.out.println(date1);

        // 按照默认格式(yyyy-MM-dd)的字符串,使用parse()方法进行转换
        LocalDate date2 = LocalDate.parse("2024-09-11");
        System.out.println(date2);

        // 按照默认格式(yyyy-MM-ddTHH:mm:ss)
        LocalDateTime dateTime1 = LocalDateTime.of(2024,9,11,17,50,30);
        LocalDateTime dateTime2 =LocalDateTime.parse("2024-09-11T17:50:30");
        System.out.println(dateTime1);
        System.out.println(dateTime2);

        // 按照默认格式(HH:mm:ss)
        LocalTime time1 = LocalTime.of(17,50,30);
        LocalTime time2 =LocalTime.parse("17:50:30");
        System.out.println(time1);
        System.out.println(time2);
    }

3. 日期计算

    public static void main(String[] args) {
        // 字符串格式的日期时间
        String strDatetime ="2024年12月15日";

        // 将字符串格式的日期,转换为LocalDate类型的日期对象
        LocalDate date = LocalDate.parse(strDatetime, DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
        System.out.println(date);

        // 20天前
        LocalDate date1 = date.plusDays(-20);
        System.out.println(date1);

        //20天后
        LocalDate date2 = date.plusDays(20);
        System.out.println(date2);
    }

    public static void main(String[] args) {
        //计算两个日期间隔多少天,计算间隔多少年,多少月
        LocalDate date1 = LocalDate.parse("2024-07-12");
        LocalDate date2 = LocalDate.parse("2024-09-11");

        Period period =Period.between(date1,date2);
        System.out.println("date1到date2相间隔"+period.getYears()+"年"+period.getMonths()+"月"+period.getDays()+"天");

        long day = date2.toEpochDay() - date1.toEpochDay();
        System.out.println(date2+"和"+date1+"相差"+day+"天");
    }

4. 获取指定日期

    public static void main(String[] args) {
        LocalDate today = LocalDate.now();

        //获取当前月第一天
        LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println("当前月第一天:"+firstDayOfThisMonth);

        //获取本月最后一天
        LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("当前月最后一天:"+lastDayOfThisMonth);

        // 获取下一天
        LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
        System.out.println("下一天(次月第一天):"+nextDay);

        LocalDate nextDay2 = today.plusDays(1);
        System.out.println("当前下一天:"+nextDay2);

        //获取当年最后一天
        LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
        System.out.println("当年最后一天:"+lastday);

        //获取当年最后一个周
        LocalDate lastMondayOfThisYear = lastday.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY));
        System.out.println("当年最后一个周一:"+lastMondayOfThisYear);
    }
相关推荐
码力码力我爱你5 分钟前
C HTML格式解析与生成之gumbo
c语言·开发语言·html
工程师老罗14 分钟前
Java笔试面试题AI答之设计模式(4)
java·开发语言·设计模式
KuaiKKyo17 分钟前
c++9月20日
java·c++·算法
muzi_liii19 分钟前
C++类和对象(下)
开发语言·c++
zero.cyx28 分钟前
JS函数部分
开发语言·前端·javascript
xmh-sxh-131428 分钟前
java缓存介绍
java
超级小的大杯柠檬水29 分钟前
SpringBoot lombok(注解@Getter @Setter)
java·前端·spring
国通快递驿站30 分钟前
理解JVM中的死锁:原因及解决方案
android·java·jvm·spring·诊断
一丝晨光30 分钟前
语言的条件语句
java·开发语言·c++·程序员·c·条件语句·algol
Kixuan21432 分钟前
ES学习笔记
java·笔记·学习·elasticsearch·搜索引擎