函数式编程-Stream流

函数式编程-Stream流

作用:
处理大数量集合:并行流,多线程处理
代码可读性高
消灭嵌套地狱

1、Lambda表达式

  • 要求:接口,并且只有一个抽象方法
  • 区别:函数式编程,不同于面对对象。不关注类名、方法名;关注参-数、方法体
  • 格式:删除参数、方法体外部分,在中间加 ->

lambda表达式再简化:

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略

2、Stream流使用:

2.1、创建流

获取流对象

  • 单列集合:list.stream;
  • 数组:Arrays.stream(arr); Stream.of(arr);
  • 双列集合:转换为单列集合,在转换为流 map.entrySet().stream(); 或keySet();等转换

2.2、中间操作

中间操作,返回值都是stream流

  • filter 过滤,符合条件保存在集合中
  • map(new Function<Ob1,Ob2>) 计算、数据类型的转换;将现在流中类型Ob1转换为Ob2,返回Ob2
  • distinct 去重,依赖equals方法,需要重写equals方法。
  • sorted 排序:
    • 空参的sorted方法需要流中元素实现了Comparable接口
    • 有参的sorted方法,在内部类里定义比较
  • limit 设置流的最大长度,超出部分抛弃掉
  • skip 跳过流中前n元素,留下之后的
  • flatMap
    把一个对象转换为多个对象成为流中的元素。一个对象中的某个属性是list集合,将这些对象的属性都加入流中处理。

2.3、终结操作

流操作最后必须有终结操作,才会执行前面的其他操作。

  • foreach 将元素遍历进行操作
  • count 获取流中元素的个数
  • max/min 获取流中的最值,返回Optional
  • collect(Collectors.toList()) 将流对象转换为集合

2.4、查找与匹配

  • anyMatch 判断是否有匹配的,有任意一个匹配的,结果为true

  • allMatch 判断是否都符合

  • noneMatch 判断都不符合

  • findAny 获取任意一个元素

  • findFirst 获取流中的第一个元素

  • reduce 归并:对流中数据按照你指定的计算方式计算出一个结果。(缩减操作)

//reduce两个参数内部原理
//遍历流中元素,与初始值进行运算,返回结果
T result = identity;
for(T element : this stream){
	result = accumulator.apply(result,element)
}
return result;

例子:求所有作者年龄的和

List<Author> authors = getAuthors();
Integer sum = authors.stream()
			.distinct()		//去重
			.map(author -> author.getAge())		//类型转换,作者对象转换为年龄Integer 
			.reduce(0,(result,element) -> result + element);//初始值为0,每个年龄与初始值相加
System.out.println(sum);	//输出年龄的和

2.5、注意事项

  • 惰性求值:没有终结操作,中间操作不会执行
  • 流是一次性的:一个流对象经过一个终结操作后,这个流不能再被使用
  • 不会影响原数据:流中的处理,正常情况下不会影响原来集合中的元素

3、Optional

作用:判断对象是否为空,避免空指针异常

3.1、获取optional对象

//获取optional对象
Author author = getAuthor(); 
Optional<Author> authorOptional = Optional.ofNullable(author); 
	//获取optional对象,mybatis 3.5后支持直接返回optional对象
	//开发中从数据库查数据,可直接返回Optional<Author>对象,由框架封装
    public static Optional<Author> getAuthorOptional(){
        Author author = new Author(12, "xy");
        return Optional.ofNullable(author);
    }

3.2、安全地消费值

        authorOptional.ifPresent(new Consumer<Author>() {
            @Override
            public void accept(Author author1) {
                System.out.println(author1.getName());
            }
        });

3.3、安全地获取值

3.3.1、orElseGet
        //设置默认值。有值则返回该值;如果为null没有值,则返回new Author()默认值
        Author author = authorOptional.orElseGet(new Supplier<Author>() {
            @Override
            public Author get() {
                return new Author();
            }
        }); 

orElseGet源码

    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
3.3.2、orElseThrow
        try {
        	//有值则返回值,没有值则抛出自定义的异常,可用于spring中统一异常管理
            Author author2 = authorOptional1.orElseThrow(new Supplier<Throwable>() {
                @Override
                public Throwable get() {
                    return new RuntimeException("数据为null");
                }
            });
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

3.4、过滤

		//返回年龄大于18岁的optional对象,不大于18岁被过滤掉
        Optional<Author> author3 = authorOptional1.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge() > 18;
            }
        });
//过滤后消费
authorOptional1.filter(author22 -> author22.getAge() > 18)
			   .ifPresent(author23 -> System.out.println(author23));

3.5、判断

isPresent判断是否存在数据。为空则返回false;如果不为空则返回true

        if (authorOptional1.isPresent()){
            System.out.println(authorOptional1.get().getName());
        }

3.6、类型转换

		将作家集合转换为书的集合
        Optional<Object> optionalBooks = 
        authorOptional1.map(new Function<Author, Object>() {
            @Override
            public Object apply(Author author) {
                return author.getBook();
            }
        });

4、函数式接口

//接口中只有一个抽象方法(可以有default修饰的默认方法),该接口为函数式接口。
//注解@FunctionalInterface标注,一定是函数式接口
@FunctionalInterface
public interface InterfaceA {
    void test();
}

4.1、常见函数式接口

  • Consumer 消费接口
    根据参数列表(T t)和返回值类型(void),可对传入参数进行消费。
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
  • Function 计算转换接口
    根据参数列表(T t)和返回值类型(R),可将参数T转换为R进行返回。
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
  • Predicate 判断接口
    根据转入条件进行判断,返回判断结果
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
  • Supplier 生产型接口
    没有参数,需要返回对象。我们可以在方法中创建对象,把创建好的对象返回
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

4.2、常见默认方法

多用于自定义的函数式方法。

  • Predicate 中的 and() 方法。短路与 &&。
        authorOptional1.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge() > 18;  //可替换为 author.getAge() > 18 && author.getName().length() < 5
            }
        }.and(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getName().length() < 5;
            }
        })).ifPresent(new Consumer<Author>() {
            @Override
            public void accept(Author author) {
                System.out.println(author);
            }
        });
  • Predicate 中的 or() 方法。
  • Predicate 中的 negate() 方法,取反。

5、方法引用

在使用lambda时,如果方法体中只有一个方法的调用的话(包括构造方法),可以用方法引用进一步简化代码。

5.1、基本格式

类名或对象名 ::方法名

5.2 使用(待续)

快捷键 alt + 回车 ,replace lambda with method reference。

6、高级用法

6.1、取消自动装拆箱

		//将age自动装箱为Integer,每有一个操作都会装拆箱,数据量大时浪费时间。
        authors.stream()
                .map(new Function<Author, Integer>() {
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge() + 10;
                    }
                })
		//用mapToInt返回int类型的值。
        authors.stream()
                .mapToInt(new ToIntFunction<Author>() {
                    @Override
                    public int applyAsInt(Author author) {
                        return author.getAge();
                    }
                })

6.2、并行流

有大数据量时,使用多线程进行处理。

authors.stream().parallel()
                .peek(new Consumer<Author>() {   //peek()中间操作,可用于调试
                    @Override
                    public void accept(Author author) {
                        System.out.println(author + Thread.currentThread().getName());  //查看线程名
                    }
                })
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Stream 是 Java 8 提供的一个用于处理集合数据的函数式编程 API。Stream API 可以让我们以一种声明式的方式处理集合数据,避免了传统的迭代方式,使代码更加简洁和易读。 而(Stream)是一个来自数据源的元素队列并支持聚合操作。元素是特定类型的对象,形成一个队列。操作可以执行顺序或并行。Java 中的 Stream API 可以使得我们可以使用一种类似于 SQL 语句在集合中执行操作。 Stream API 的主要特点如下: - Stream 不存储数据,它们只是在源的基础上提供了一种视图。 - Stream 操作是延迟执行的,只有当终止操作调用时才会执行。 - Stream 可以操作集合、数组等数据源。 - Stream 提供了丰富的中间操作和终止操作,可以实现过滤、映射、排序、聚合等功能。 函数式接口(Functional Interface)是 Java 8 中引入的一个概念,它是只包含一个抽象方法的接口。Stream API 使用了函数式接口作为其操作的参数,例如 filter、map、reduce 等方法都接受函数式接口作为参数,以便进行相应的操作。 在 Stream API 中,常用的函数式接口有 Predicate、Function、Consumer、Supplier 等,它们可以通过 Lambda 表达式或方法引用来创建,并可以与操作相结合使用,实现各种数据处理操作。 希望这个回答能够解决你对 Stream 函数式接口的疑问。如果还有其他问题,请随时提问!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值