java8学习总结

一、Lambda表达式
1、Lambda表达式语法

三个部分:参数列表,箭头,主体
eg:
(参数列表) -> 主体;

()->  System.out.println("Hello World,Lambda");
2、从匿名类到Lambda的转换

代码:

public static void main(String[] args) {

        /**
         * 匿名内部类
         */
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World");
            }
        };
        runnable.run();

        /**
         * Lambda表达式的实现
         */
        Runnable runnable1 = () -> System.out.println("Hello World,Lambda");
        runnable1.run();
    }

执行结果
在这里插入图片描述

3、Lambda表达式的使用场景

在函数式接口中使用

4、类型检查

Lambda的类型是从使用Lambda的上下文推断出来的
在这里插入图片描述

5、类型推断

Java编译器会从上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式
在这里插入图片描述

6、使用局部变量

局部变量;在主体引用之外声明的变量。注意,局部变量必须显式声明为final,或事实上是final
在这里插入图片描述

二、函数式接口

定义:函数式接口就是只定义了一个抽象方法的接口
eg:

/************************* Runnable 接口 ********************** /
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

/************************* Comparator 接口 ********************** /
@FunctionalInterface
public interface Comparator<T> {

int compare(T o1, T o2);

......
}
1、@FunctionalInterface注解

该标注表示该接口会设计成一个函数式接口。如果你用@FunctionalInterface定义了一个接口,而它不是函数式接口的话,编译器将返回一个提示原因的错误。例如,错误消息可能是“Multiple non-overriding abstract methods found in interface Foo”,表明存在多个抽象方法。请注意,@@FunctionalInterface不是必需的,但对于为此涉及的接口而言,使用它是比较好的做法。

2、常见函数式接口

Java内置四大函数式接口
在这里插入图片描述

3、专门为基本类型设计的函数式接口,避免装箱拆箱操作

eg:
在这里插入图片描述

三、引用
1、方法引用
  • 类::静态方法
  • 类::实例方法
  • 对象::实例方法

第一种类似于静态类的调用,第二种引用的思想就是你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。第三种方法引用指的是,你在Lambda中调用一个已经存在的外部对象中的方法
在这里插入图片描述

2、构造器引用

格式

类名::new

其中,构造器参数列表要与接口中抽象方法的参数列表一致
在这里插入图片描述

3、数组引用
四、流

定义:从支持数据处理操作的源生成的元素序列
1、流与集合
集合与流之间的差异就在于什么时候进行计算。集合是急切计算的,而流则是按需计算的,具有延时性。例如谷歌搜索,若是集合,则会将匹配的所有信息一次性查出放入,而流可能就是一页一页的查询,即你看完当前页,点击下一页时才会触发下一页数据的查询。
2、和迭代器类似,流只能遍历一次
3、streams库的内部迭代可以自动选择一种适合你硬件的数据表示和并行实现,流利用内部迭代:迭代通过filter、map、sorted等操作被抽象掉
4、流操作

  • 中间操作
  • 终端操作

注意:除非流水线上触发一个终端操作,否则中间操作不会执行任何处理
在这里插入图片描述

五、流的使用

1、映射map:对流中的每一个元素执行该操作,其本质是经一个对象映射成另一个对象
2、流的扁平化:map和flatmap
在这里插入图片描述
其中stream中封装的对象对应map映射后的类型。flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
3、查找和匹配:allMatch、anyMatch、noneMatch、findFirst和findAny
注意:findFirst和findAny,findAny在并行上较findFirst限制较少。
4、规约:reduce

//接受初始值
int product = numbers.stream().reduce(1, (a, b) -> a * b);

//不接受初始值
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

5、状态

  • 有状态:需要知道之前状态,如reduce、sum、max
  • 无状态:不需要知道内部迭代状态,如map或filter
    在这里插入图片描述
    六、Collectors类
    方法	返回类型	作用	示例toList	List	把流中元素收集到List	Listemps=list.stream().collect(Collectors.toList());toSet	Set	把流中元素收集到Set	Setemps=list.stream().collect(Collectors.toSet());toCollection	Collection	把流中元素收集到创建的集合	Collectionemps=list.stream().collect(Collectors.toCollection(ArrayList::new));counting	Long	计算流中元素的个数	longcount=list.stream().collect(Collectors.counting());summingInt	Integer	对流中元素的整数属性求和	inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));averagingInt	Double	计算流中元素Integer属性的平均值	doubleavg=list.stream().collect(Collectors.averagingInt(Employee::getSalary));summarizingInt	IntSummaryStatistics	收集流中Integer属性的统计值。如:平均值,最大值等	IntSummaryStatisticsiss=list.stream().collect(Collectors.summarizingInt(Employee::getSalary));joining	String	连接流中每个字符串	Stringstr=list.stream().map(Employee::getName).collect(Collectors.joining());maxBy	Optional	根据比较器选择最大值	Optionalmax=list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));minBy	Optional	根据比较器选择最小值	Optionalmin=list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));reducing	归约产生的类型	从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值	inttotal=list.stream().collect(Collectors.reducing(0,Employee::getSalar,Integer::sum));collectingAndThen	转换函数返回的类型	包裹另一个收集器,对其结果转换函数	int how=list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size));groupingBy	根据某属性值对流分组,属性为K,结果为V	根据某属性值对流分组,属性为K,结果为V	Map<Emp.Status, List> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));partitioningBy	Map<Boolean,List>	根据true或false进行分区	Map<Boolean,List>vd=list.stream().collect(Collectors.partitioningBy(Employee::getManage));

1、oining工厂方法有一个重载版本可以接受元素之间的分界符

Stringstr=list.stream().map(Employee::getName).collect(Collectors.joining(","));

2、ruduce与collect的区别:educe方法旨在把两个值结合起来生成一个新值,它是一个不可变的规约。而collec方法的设计就是要改变容器,从而累积要输出的结果
3、groupingby的可以接受第二个参数,与其他收集器联合起来使用,例如

Map<Dish.Type, Integer> totalCaloriesByType =menu.stream().collect(groupingBy(Dish::getType,summingInt(Dish::getCalories)));
七、新时间日期API
1、LocalDate、LocalTime、LocalDateTime

这些类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间
在这里插入图片描述

2、Duration与Period

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

3、时间调整期

在这里插入图片描述

4、总结
  • 新版的日期和时间API中,日期时间对象是不可变的
  • 操纵日期和时间时,操作的结果总是返回一个新的实例,老的日期时间对象不会发生变化。
八、总结
  1. Lambda表达式其实就是对匿名内部类的演变,其方法主体其实就是匿名内部内方法的主体。
  2. stream流采用的内部迭代通常比for-each的显示迭代效率更高
  3. stream流在执行中间操作时,只是将一系列操作中间操作组合,当有终端操作时才会全部触发
九、日常问题
1、list转map的坑

参考:Java8新特性Stream之list转map及问题解决

结论:用Collectors的toMap方法转换List,一般会遇到两个问题。一个是转换map,key重复问题;另一个是空指针异常,即转为map的value是null
(1)转换map,key重复问题解决方案

  • 重复时用后面的value 覆盖前面的value
  • 重复时将前面的value 和后面的value拼接起来
  • 重复时将重复key的数据组成集合

(2)空指针异常:在转换流中加上判空,即便value为空,依旧输出

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值