JDK8新特性【函数式接口和Stream流】

一、函数式接口

接口中只有一个抽象方法时,该接口就是函数式接口.

为什么叫做函数式接口?因为这种接口,放在方法中当参数时,可以改造成lambda,进行运算.


Java提供了一个注解可以校验接口是否是函数式接口

@FunctionalInterface

Java中提供了几个特别常用的函数式接口

  • Supplier 供应,即返回一个数据 (无参有返回值的方法)

  • Consumer 消费,即给其传入数据做运算 (有参无返回值的方法)

  • Function 函数,传入2个参数,用于转换数据的 (有参有返回值的方法)

  • Predicate 判断,返回时boolean (有参,返回值是boolean)


为什么设计这些接口? 因为之前演示lambda时,需要自己设计一些IA , IB等接口,现在可以直接使用这些接口

1、 Supplier

JDK中Supplier.java源码

@FunctionalInterface
public interface Supplier<T> {
​
    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
// 该接口用来返回一个数据,所以叫供应商
// 其实就是无参数有返回值的接口,用的时候就是无参有返回值的lambda

练习,设计方法,通过Supplier接口,获得字符串的长度

  public static void main(String[] args) {
        get(() -> {
            int length = "asdafasfasdf".length( );
            return length;
        });
    }
​
    // 设计方法,方法的参数是Supplier
    // 需求1:获得字符串的长度
    public static void get(Supplier<Integer> supplier) {
        Integer i = supplier.get( );
        System.out.println(i );
    }

2、  Consumer

JDK中Consumer.java源码

@FunctionalInterface
public interface Consumer<T> {
​
    /**
     * Performs this operation on the given argument.
     * 给传入一个值,对该值进行操作
     * @param t the input argument
     */
    void accept(T t);
}
// 其实就是有参数无返回值的接口,用的时候就是有参无返回值的lambda

3、 Function

JDK中Function.java源码

@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);
}
// 该接口用于,转换数据
// 其实就是有参数有返回值的接口,用的时候就是有参有返回值的lambda

练习,设计方法,将传入的字符串数字,转为整形数字

// 设计方法,将传入的字符串数字,转为整形数字
    public static void to(Function<String,Integer> function) {
        Integer i = function.apply("1111");
        System.out.println(i  + 2);
    }
    public static void main(String[] args) {
        to(t -> Integer.parseInt(t));
    }

4、 Predicate

JDK中Predicate.java源码

@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);
}

判断数据是否是偶数

 // 设计方法,判断数据是否是偶数
    public static void pd(Predicate<Integer> predicate) {
        boolean test = predicate.test(1);
        System.out.println(test );
    }
​
    public static void main(String[] args) {
        pd(i -> i % 2 == 0);
    }

5、 总结

这些函数式认识即可,一般是用在下面Stream流中的

现在学习这几个函数式接口,就是让大家知道这些接口特性:

  • 比如有无参数,参数类型和个数

  • 比如有无返回值,返回值类型

以及用法,就是这些接口一般都会用在哪种场景下?

  • Supplier接口的方法一般用于 获得数据

  • Consumer接口的方法 一般用于 处理数据

  • Function接口的方法一般用于 转换数据

  • Predicate接口的方法一般用于 判断数据

二、Stream流[重点]

Stream流,不要和之前学的IO流进行联想,他们之间没有关系.

IO流,数据像水流一样在传输,即IO流强调是传输数据

Stream流,数据像车间流水线,在一直往下走动,不是保存数据,也不纯粹的传输数据,而是像车间流水线一样,在处理数据.

1、 获得流

Java提供了几种方式,可以让我们获得Stream流

  1. [集合创建流]Collection 接口的 stream()或 parallelStream()方法

  2. [自由值创建]静态的 Stream.of(...)、Stream.empty()方法

  3. [数组创建流]Arrays.stream(array)

  4. 静态的 Stream.generate()方法生成无限流,接受一个不包含引元的函数

  5. 静态的 Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数

  6. Pattern 接口的 splitAsStream(input)方法

  7. 静态的 Files.lines(path)、Files.lines(path, charSet)方法

  8. 静态的 Stream.concat()方法将两个流连接起来

   public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>( );
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        // 方式1: 从集合获得流
        Stream<Integer> stream = list.stream( );
​
        int[] arr = {1,2,3,4,5};
        // 方式2: 从数组获得流
        IntStream stream2 = Arrays.stream(arr);
​
​
        // 方式3: 直接创建流
        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
​
    }

2、 Stream操作[重点]

Stream流就是流式处理数据,流的操作有很多种

  • 中间操作(真正处理数据的操作)

    • 中间操作就是执行完返回的是一个流,即可以继续执行流操作

    • 敲代码来说,就是使用中间操作的方法,写完继续再.调用其他方法

  • 终止操作(将操作完的结果返回)

    • 敲代码来说,调用终止方法,代码就结束;

操作函数说明
中间操作filter(Predicate)将结果为false的元素过滤掉
中间操作map(Function)转换元素的值,可以用方法引元或者lambda表达式
中间操作flatMap(Function)若元素是流,将流摊平为正常元素,再进行元素转换(合并两个流为一个流)
中间操作limit(long n)保留前n个元素
中间操作skip(long n)跳过前n个元素
中间操作concat(Stream s1, Stream s2)将两个流拼接起来
中间操作distinct()剔除重复元素
中间操作sorted()将Comparable元素的流排序
中间操作sorted(Comparator)将流元素按Comparator排序
中间操作peek(Consumer)流不变,但会把每个元素传入fun执行,可以用作调试
终结操作max(Comparator)取最大值
终结操作min(Comparator)取最小值
终结操作count()统计元素数量
终结操作findFirst()获得流的第一个元素
终结操作findAny()返回任意元素
终结操作anyMatch(Predicate)任意元素匹配时返回true
终结操作allMatch(Predicate)所有元素匹配时返回true
终结操作noneMatch(Predicate)没有元素匹配时返回true
终结操作reduce(Function)从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数
终结操作iterator()迭代器迭代元素
终结操作forEach(Consumer)lambda的方式迭代
终结操作forEachOrdered(Consumer)可以应用在并行流上以保持元素顺序

2.1 中间操作

下面演示流的操作使用 - 中间操作

public class Demo2 {
​
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>( );
        list.add(1);
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        // 方式1: 从集合获得流
        Stream<Integer> stream = list.stream( );
        /**
         * filter是过滤,满足指定的条件数据保留
         * forEach是遍历
         */
        // 过滤保留偶数
        // stream.filter(e -> e % 2 == 0).forEach(e -> System.out.println(e ));
        /**
         * map 是转换
         */
        // 将数字扩大10倍
        // stream.map(e -> e * 10).forEach(e -> System.out.println(e ));
​
        /**
         * limit限制,只要流中的前几个数据
         */
        //stream.limit(2).forEach(s -> System.out.println(s ));
        // 跳过
        //stream.skip(2).forEach(s -> System.out.println(s ));
​
​
        // Stream<Integer> s1 = Stream.of(1, 3, 5, 7);
        // Stream<Integer> s2 = Stream.of(2, 4, 6, 8);
        // // 合并
        // Stream<Integer> s3 = Stream.concat(s1, s2);
        // s3.forEach(s -> System.out.println(s));
​
        /**
         * 终结操作 max
         */
        // Optional<Integer> optional = stream.max((o1, o2) -> o1 - o2);
        // System.out.println(optional );// 这个Optional中包含结果
        // // 需要再取出
        // Integer max = optional.get( );
        // System.out.println(max );
​
        Integer max = stream.max((o1, o2) -> o1 - o2).get( );
    }
}
public class Demo7 {
​
    public static void main(String[] args) {
        // Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
​
        // 终结操作,遍历
        // stream.forEach(s -> System.out.println(s ));
​
        // filter过滤数据,判断结果为true就保留
        // stream.filter(x -> x % 2 == 0).forEach(s -> System.out.println(s));
​
        // map是转换,
        // 将流中数据>1的保留,且将它们转换为字符串输出
        // stream
        //         .filter(x -> x > 1)
        //         .map(x -> String.valueOf(x))
        //         .forEach(s -> System.out.println(s));
​
        // flatMap 摊平,将两个集合/数组/流转成一个
        // Stream<String> java = Stream.of("java", "python");
        // List<String> collect = java.flatMap(s -> Arrays.stream(s.split("")))
        //         .collect(Collectors.toList( ));
        //
        // System.out.println(collect );
        //
        // ArrayList<Integer> l1 = new ArrayList<>( );
        // l1.add(1);
        // l1.add(3);
        // l1.add(5);
        //
        // ArrayList<Integer> l2 = new ArrayList<>( );
        // l2.add(2);
        // l2.add(4);
        // l2.add(6);
        //
        // ArrayList<List> l3 = new ArrayList<>( );
        // l3.add(l1);
        // l3.add(l2);
        // System.out.println(l3 );
        //
        // Object l4 = l3.stream( ).flatMap(s -> s.stream( )).collect(Collectors.toList( ));
        // System.out.println(l4 );
​
        // Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
        // limit 保留前n个,skip 跳过 n个
        // stream.limit(4).skip(2).forEach(s -> System.out.println(s ));
​
    }
​
}

2.3 注意事项

Stream流的操作注意事项

  1. 流的操作只能使用一次,也就是说执行过终结操作后不能再继续使用

    否则报错报错IllegalStateException stream has already been closed

  2. 使用中间操作,返回新的流

  3. 没有终止操作,就不会有结果,换句话说,没有终结操作,中间操作是 不会执行的

    public static void test2() {
        Stream<Integer> stream = Stream.of(1, 2, 3);
        stream.filter((e) -> {
            System.out.println("正在过滤元素:"+e );
            return e % 2 == 0;
        });
        // 没有终结操作,中间的filter不会执行,输出语句不会执行
    }

3、 流的收集

流操作完,将数据流中的数据再返回成数组和集合 --> 这就是收集流

将流收集到集合或数组中

  • collect() 收集到集合

    • collect(Collectors.toList( )) 将stream流中的数据,收集到List集合

    • collect(Collectors.toSet( )) 将stream流中的数据,收集到set集合

  • toArray 收集到数组

    ArrayList<Integer> list = new ArrayList<>( );
        list.add(3);
        // 获得流
        Stream<Integer> stream = list.stream( );
        // 先过滤数据只保留偶数
        // 后对数据进行降序排序,
        // 去除重复元素,
        // 将元素转成String类型
        // 变成ArrayList<String>返回
        List<String> list2 = stream.filter(e -> e % 2 == 0)
                .sorted((o1, o2) -> o2 - o1)
                .distinct( )
                .map(e -> String.valueOf(e))
                .collect(Collectors.toList( ));// 收集为List集合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值