Java SE(十四)之 Java 8新特性(Lambda,Stream流,方法引用等)

Java 8

Java8可以是一个里程碑的版本,提供了很多有用的特性。

Lambda

1.概述

作用:简化匿名内部类的代码写法

首先回顾一下匿名内部类:
(为什么要引入匿名内部类?是因为可以方便创建子类对象,最终目的是为了简化代码编写,具体可以指路:匿名内部类

// 首先创建一个接口
interface inter{
    
    
    public void eat();
}

public class AnonymousDemo
{
    
    
	public static void main(String[] args) {
    
    
	// 直接使用匿名内部类,重写eat方法并调用
        new inter(){
    
    
            @Override
            public void eat() {
    
    
                System.out.println("正在调用eat方法");
            }
        }.eat();
    }
}

但是,Lambda看到这里还是觉得不够简便,所以进一步开始简化!

Lambda语法:

( parameter-list ) -> { expression-or-statements }
注:-> 是语法形式,无实际含义

所以上面的可以简化成:

interface inter{
    
    
    public void eat();
}
public class AnonymousDemo {
    
    
    public static void main(String[] args) {
    
    
        // 这里的eat函数没有参数,另外实现语句只有一句,就省略{}
        inter myInter = () -> System.out.println("正在调用eat方法");
        myInter.eat(); // 调用eat方法
    }
}

Lambda表达式本身就是一个接口的实现,Lambda表达式只能简化函数式接口的匿名内部类的写法形式

什么是函数式接口?
首先必须是接口、其次接口中有且仅有一个抽象方法的形式
常会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口

最后用两张图进行Java8 和Java7的对比,参考https://www.zhihu.com/question/20125256/answer/324121308

第一张图,和上面的例子很像,原本java7必须得按照面向对象那套流程;而Java 8的Lambda可以直接将接口的实现赋值给一个变量。
在这里插入图片描述

第二张图,是说明上面那个“变量”可以当作参数传给其他函数(传统的Java 7必须要求定义一个实现类)

在这里插入图片描述

2.应用场景

直接通过几种不同场景来熟悉Lambda

借用线程中的接口来演示一下
(1)无参数,无返回体

() -> System.out.println("零参数 lambda");

(2)一个参数,无返回值

// 实现Function接口
Function<Integer, Integer> add = (x) -> x + 1;
int result = add.apply(5); // result = 6

(3)两个参数,有返回值

public static void findMaxValue(int num1,int num2){
    
    
        Comparator<Integer> comparatorMax = (o1, o2) ->{
    
    
            log.info("o1:{}",o1);
            log.info("o2:{}",o2);
            return (o1<o2)? o2 :(o1);
        };
        log.info("findMaxValue:{}",(comparatorMax.compare(num1,num2)));
    }

3.省略规则

  • 参数类型可以省略不写(编译器会根据上下文判断)
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略。
  • 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!

Stream流

1. 简介

在这里插入图片描述

作用:用来简化数组和集合的操作

简单说就是 Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等

可以先看一个小例子:

要求是:创建一个集合,存储多个字符串元素,把集合中所有以"张"开头的元素存储到一个新的集合,把"张"开头的集合中的长度为3的元素存储到一个新的集合最后遍历

如果按照正常编程,可能得挨个遍历对元素进行判断处理,但是Stream编程就可以一步到位

public class StreamDemo {
    
    
    public static void main(String[] args) {
    
    
        //集合的批量添加
        ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良"));

        //Stream流
        list1.stream().filter(s->s.startsWith("张"))
                .filter(s->s.length() == 3)
                .forEach(s-> System.out.println(s));
    }
}

Stream流的主要构成(三类方法)

  • 获取Stream流:创建一条流水线,并把数据放到流水线上准备进行操作
  • 中间方法:流水线上的操作,一次操作完毕后,还可以继续进行其他操作
  • 终结方法:一个Stream流只能有一个终结方法,是流水线上最后一个操作

下面将对三个组成进行分别介绍

2. Stream流的创建

Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能。

(1)Collection集合获取Stream流的方式

可以使用Collection接口中的默认方法stream()生成流

// 获取当前集合对象的Stream流
default Stream<E> stream()

(2) Map体系集合

把Map转成Set集合,间接的生成流

(3)数组获取Stream流的方式

通过Arrays中的静态方法stream生成流

方法 含义
public static Stream stream(T[ ] array) 获取当前数组的Stream流
public static Stream of(T… values) 获取当前数组/可变数据的stream流
public class StreamDemo {
    
    
    public static void main(String[] args) {
    
    
        //Collection体系的集合可以使用默认方法stream()生成流
        List<String> list = new ArrayList<String>();
        Stream<String> listStream = list.stream();

        //Map体系的集合间接的生成流
        Map<String,Integer> map = new HashMap<String, Integer>();
        Stream<String> keyStream = map.keySet().stream();
        Stream<Integer> valueStream = map.values().stream();
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

        //数组可以通过Arrays中的静态方法stream生成流
        String[] strArray = {
    
    "hello","world","java"};
        Stream<String> strArrayStream = Arrays.stream(strArray);
}

3. 常用中间方法

方法 含义
stream filter(Predicate< ? super T> predicate) 用于对流中的数据进行过滤
stream limit( long maxsize) 获取前几个元素
stream skip(long n) 跳过前几个元素
stream distinct( ) 去除流中重复的元素。依赖(hashCode和equals方法)
static stream concat(Stream a,Stream b) 合并a和b两个流为一个流

中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程

在Stream流中无法直接修改集合、数组中的数据

4. 常用终结方法

方法 含义
void forEach(Consumer action) 对此流的每个元素执行遍历操作
long count() 返回此流中的元素数

终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了

5. 收集Stream流

把Stream流操作后的结果数据转回到集合或者数组中去

方法名 说明
R collect(Collector collector) 把结果收集到集合中

具体收集方法(Collector工具类):

方法名 说明
public static Collector toList() 把元素收集到List集合中
public static Collector toSet() 把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中

方法引用

1.方法引用符 ::

2.引用类方法

猜你喜欢

转载自blog.csdn.net/ji_meng/article/details/127349025