java8新特性学习 Lambda Stream 新日期时间API

主要内容:

一、Lambda表达式

二、函数式接口

三、方法引用与结构器引用

四、Stream API

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

六、更新时间日期API

七、其他新特性

优点:速度更快、代码更少(增加了新的语法Lambda表达式)、强大的Stream API、便于并行、最大化减少空指针异常Optional

一、Lambda表达式: 简化开发

1、简化匿名内部类的写法,简化接口的实现。

lambda表达式的基础语法:Java8中引入了一个新的操作符  "->" 箭头操作符或lambda操作符,箭头操作符将lambda表达式拆分成两部分。

左侧:对应lambda表达式的参数列表。 ( 接口的抽象方法的参数列表)

右侧:对应lambda表达式中所需要执行的功能。即Lambda体   (对抽象方法的实现)

语法格式一:接口无参数,无返回值。实现代码只有一行的时候{}可以省略

()-> {实现功能的代码}

()->实现功能的代码

语法格式二:接口一个参数,无返回值。一个参数的时候小括号可以不写,实现代码只有一行的时候{}可以省略

(e)-> {实现功能的代码}

e->{实现功能的代码}

e->实现功能的代码

语法格式三:接口一个参数,有返回值。一个参数的时候小括号可以不写,实现代码只有一行的时候{}可以省略

(e)-> {return 实现功能的代码}

e->{return 实现功能的代码}

e->实现功能的代码

语法格式四:接口有多个参数,有返回值。实现代码只有一行的时候 return  和 {} 都可以省略

(x,y)-> {return 实现功能的代码}

(x,y)-> 实现功能的代码

 语法格式五:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器会通过上下文推断出数据类型,即“类型推断”

二、Lambda表达式需要“函数式接口”的支持

函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰  检查是不是函数式接口。有这个注解的接口,只能有一个抽象方法,否则会报错。

函数式接口我们不用全部都写,java8已经定义了常用的函数式接口,除非有特殊的情况下才需要我们自己写。

Java8内置的四大核心函数式接口:

Consumer<T> :(传一个参数,没有返回值,只对参数进行一些处理)

                        消费型接口     void   accept(T t);

public static void main(String[] args) {
        happy(100D,(e)->{
            //实现功能,进行消费,无返回值
            System.out.println("消费了"+e+"元,用于happy");
        });
    }
    public static void happy(Double money, Consumer<Double> consumer){
        consumer.accept(money);
    }

Supplier<T>: (调用方法,返回对象)

                        供给型型接口     T    get();

public static void main(String[] args) {
        getNumIntegerList(10,()->{
           //供给方法,无参数,有返回值,实现功能,
            // 返回值如何产生
            return (int)(Math.random()*100);
        });
    }
    public static List<Integer> getNumIntegerList(int num, Supplier<Integer> supplier){
        List<Integer> integerList = new ArrayList<>();
        for (int i =0;i<num;i++){
            Integer integer = supplier.get();
            integerList.add(integer);
        }
        return integerList;
    }

Function<T,R>: (传入一个参数,经过处理,返回一个对象)

                        函数型接口      R   apply(T t);

public static void main(String[] args) {
        String string = strHandler("我-是-被-处-理-的-字-符-串", (str) -> str.replace("-", ""));
    }
    public static String strHandler(String string, Function<String,String> function){
        return function.apply(string);
    }

Predicate<T>:(传入一个参数,判断是否符合某种条件)

                        断言型接口      boolean   test(T t);

public static void main(String[] args) {
        List<String> stringList = Arrays.asList("ass","fasfgas","asgfaaasg","gdfvb222df","fsadvsdgdsgsd","asgf","gasgvdasfas","gdfgert");
        List<String> list = filterStr(stringList, 
                //断言型,功能:获取字符串大于7的字符串
                (str) -> str.length() > 7);
        System.out.println(list);
    }
    public static List<String> filterStr(List<String> stringList, Predicate<String> predicate){
        List<String> newStringList = new ArrayList<>();
        stringList.forEach(item->{
            if(predicate.test(item)){
                newStringList.add(item);
            }
        });
        return newStringList;
    }

三、方法引用和构造器引用:

若Lambda体中的内容有方法已经实现了,我们可以使用”方法引用“(可以理解为方法引用时Lambda表达式的另外一种表现形式)

使用的注意事项:Lambda体中调用方法的参数列表和返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。

主要有三种语法格式:

对象::实例方法名  

Consumer<String> com = (string)->System.out.println(string);
        com.accept("这是普通Lambda写法");
        PrintStream ps1 = System.out;
        Consumer<String> com1 = ps1::print;
        com1.accept("这是方法引用的写法");

类::静态方法名

Comparator<Integer> comparable = (x, y)->Integer.compare(x,y);
    Comparator<Integer> comparable1 = Integer::compareTo;

类::实例方法名 (有前提条件,第一个参数的实例方法的参数是第二个参数的时候才能用)

BiPredicate<String,String> bp = (x,y)->x.equals(y);
        BiPredicate<String,String> bp1 = String::equals;

 构造器引用

构造器引用取决于函数式接口的实现方法有几个参数,并且参数类型也要保持一致。

四、Stream API

Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似使用SQL执行数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种搞笑且易于使用的处理数据的方式。

 stream:是数据渠道,用于操作数据源

注意:

1、Stream自己不会存储元素

2、Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream

3、Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

 1、Stream的创建

//通过Collection系列集合提供的stream()或parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
        //通过Arrays中的静态方法stream()获取数组流
        Integer[] integers = new Integer[10];
        Stream<Integer> stream1 = Arrays.stream(integers);
        //通过Stream类中的静态方法 of()
        Stream<String> stream2 = Stream.of("aaaaa","bbbbbb","cccccc","ddddd");
        //创建无限流,迭代
        Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
        //生成长度为5 数据为随机数的流
        Stream.generate(()->Math.random()).limit(5).forEach(System.out::println);

2、中间操作  (只有中间操作是不会执行的,需要有终止操作才会执行),即“惰性求值”。

*筛选与切片

filter——接收Lambda,从流中排除不满足条件的元素

limit——截断流,使其元素不超过给定数量。达到了指定数量后就不会执行了

skip(n)——跳过元素,返回一个扔掉了前n个元素的流,若流中的元素不足n个,则返回一个空流,与limit互补。

distinct——筛选,通过流所生成元素的hashCode()和equals去除重复元素。

*映射

map——接收Lambda,将元素转换成其他形式或者提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并映射成一个新的元素。

flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

*排序

sorted()——自然排序(Comparable)

sorted(Comparator com)——定制排序(Comparator)

3、终止操作

*查找与匹配

allMatch——检查所有元素是否都符合条件(方法参数是一个Predicate函数接口,条件写进去)

anyMatch——检查是否存在一个或一个以上的元素符合条件(方法参数是一个Predicate函数接口,条件写进去)

noneMatch——检查是否所有元素都不符合条件(方法参数是一个Predicate函数接口,条件写进去)

findFirst——返回第一个元素

findAny——返回当前流中的任意元素

count——返回流中的总个数

max——返回流中最大值

min——返回流中最小值

*归约

reduce(T indentity, BinaryOperator) / reduce(BinaryOperator)——可以将流中元素反复结合起来,得到一个值。  (indentity 运算的初始值  BinaryOperator定义如何进行结合)

*收集

collect——将流转换成其他形式,接收一个Collector接口的实现,用于做stream中元素的汇总。

 collect方法里的Collectors能进行其他计算,包括总数,平均值、总和、最大值、最小值、分组、分区等等.....

总数:Collectors.counting(arg)

平均值:Collectors..averagingDouble(arg)

总和:Collectors.summingDouble(arg)

最大值:Collectors.maxBy(arg)

最小值:Collectors.minBy(arg)

分组:Collectors.groupingBy(arg)   

多级分组:Collectors.groupingBy(arg,Collectors.groupingBy(arg))

分区:true,false分区Collectors.partitioningBy(arg)

根据参数某个字段获取到总数,平均值、总和、最大值、最小值等数据的封装体对象Collectors.summarizingDouble(arg)

4、并行流与顺序流

        并行流就是把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

        Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作,Stream API 可以声明性的地通过parallel() 与 sequential() 在并行流与顺序流之间进行切换。

5、Optional类

Optional<T>类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

常用方法:

Optional.of(T t):创建一个Optional实例

Optional.empty():创建一个空的Optional实例

Optional.ofNullable(T t):若t不为null,创建Optional实例,否则创建空实例

isPresent():判断是否包含值

orElse(T t) :如果调用对象包含值,否则返回t

orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值

map(Function f) :如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()

flatMap(Function mapper):与map类似,要求返回值必须是Optional

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

在java8中运行接口中有default修饰的默认方法。

 

六、新时间日期API

//1、LocalDate获取日期、
        // LocalTime获取时间、
        // LocalDateTime获取日期时间,日期与时间之间 T 分隔
        //三个的使用方式类似,这里用LocalDateTime测试
        LocalDateTime localDateTime = LocalDateTime.now(); //获取当前日期时间
        LocalDateTime.of(2021,10,21,15,28,16);//获取指定年月日时分秒的时间
        //plusYears加年 plusMonths加月.....
        LocalDateTime localDateTime1 = localDateTime.plusSeconds(10);//加10秒,获取到新实例
        //minus...  减获取年月日时分秒...
        //get...   获取年月日时分秒...

        //2、Instant:时间戳(以Unix元年:1970年1月1日 00:00:00 到某个时间的毫秒值)
        Instant now = Instant.now();//获取到目前时间,默认获取以UTC时期为基础,不是电脑系统的当前时间
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));//操作偏移量,偏移8个小时
        now.toEpochMilli();//获取毫秒值
        Instant.ofEpochSecond(60);//加60秒

        //3、计算日期时间之间的操作
        //Duration:计算两个  时间  之间的间隔
        //Period:计算两个  日期  之间的间隔
        Instant now1 = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant now2 = Instant.now();
        Duration.between(now1,now2);


大多是看文档使用的东西,引用一手别人的文章,使用的时候翻翻。

Java8日期时间API详解_78KgMiao的博客-优快云博客

七、重复注解与类型注解

@Repeatable(MyAnnotations.class) //指定容器类
@Target({ElementType.TYPE, ElementType.METHOD,  ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "Java 8";
}




@Target({ElementType.TYPE, ElementType.METHOD,  ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    MyAnnotation[] value();
}




public class Test01 {

    //重复注解
    @Test
    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public void test01() throws NoSuchMethodException {
        Class<Test01> clazz = Test01.class;
        Method test01 = clazz.getMethod("test01");
        MyAnnotation[] mas = test01.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation ma : mas) {
            System.out.println(ma.value());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值