java进阶 -- 函数式接口和Stream流

函数式接口

  • 概念:有且仅有一个抽象方法的接口就叫做函数式接口。可以使用@FunctionalInterface注解检查。
    注意:一个接口是不是函数式接口和@FunctionalInterface没有任何关系,只和抽象方法的个数有关。如果这个接口不是函数式接口,
    那么加上这个注解之后就会编译报错。

          例如:JDK中的Runnable接口就是一个函数式接口
              @FunctionalInterface
              public interface Runnable {
                  public abstract void run();
              }
    
  • 使用场景:作为方法的参数或者返回值

  • JDK中常见的函数式接口

    1. Supplier:生产型接口
      T get():get()方法不需要给参数,反而给你返回一个T类型的值。

      		package com.jxufe_ldl.class02.supplier;
      
      import java.util.function.Supplier;
      
      public class SupplierDemo {
          public static void main(String[] args) {
              // 获取一个字符串
              String str = getString(() -> "于曼丽");
              System.out.println("str = " + str);
      
              // 获取一个整数
              int num = getInt( () -> 666);
              System.out.println("num = " + num);
          }
      
          private static String getString(Supplier<String> sup) {
              return sup.get();
          }
      
          private static int getInt(Supplier<Integer> sup) {
              return sup.get();
          }
      }
      	
      
    2. Consumer:消费型接口
      void accept(T t):需要一个T类型的参数,没有返回值,通过accept将T类型的数据交给我们使用(消费) (掌握)
      default Consumer<T> andThen(Consumer<? super T> after):将两个Consumer连接,分别消费数据

           例如:
               //遍历输出  (T t)
               list.forEach(num->System.out.println(num));
               System.out.println("--------------");
               //方法引用
               list.forEach(System.out::println);
       ```java
       package com.jxufe_ldl.class01;
       
       import java.util.function.Consumer;
       
       public class ConsumerDemo {
           public static void main(String[] args) {
               // 定义一个字符串数组
               String[] strArr = {"林青霞,30", "张曼玉,35", "王祖贤,33"};
       
               // 调用方法
               printInfo(strArr, (String s) -> {
                   String name = s.split(",")[0];
                   System.out.print("姓名:" + name);
               }, (String s) -> {
                   int age = Integer.parseInt(s.split(",")[1]);
                   System.out.println(",年龄:" + age);
               });
           }
           // Consumer 的泛型指定了什么类型,accept方法消费的数据就是什么类型
           private static void printInfo(String[] strArr, Consumer<String> con1, Consumer<String> con2) {
               for (String str : strArr) {
                   con1.andThen(con2).accept(str);
               }
           }
       }
       
       ```
      
    3. Predicate:判断型接口
      boolean test(T t):将给定的T类型的参数在test方法中进行条件判断,返回判断结果。

      package com.jxufe_ldl.class01;
      
      import java.util.function.Predicate;
      
      public class PredicateDemoo02 {
          public static void main(String[] args) {
              boolean b1= checkString("hello", (String str) -> {
                  return str.length() > 8;
              });
      
              System.out.println(b1);
      
              boolean b2 = checkString("hello", str -> str.length() > 8, str -> str.length() < 15);
              System.out.println(b2);
          }
      
          // 判断给定的字符串是否满足要求
          private static boolean checkString(String str, Predicate<String> pre) {
      //        return pre.test(str);
      
              return pre.negate().test(str);
          }
      
          private static boolean checkString(String str, Predicate<String> pre1, Predicate<String> per2){
      //        return pre1.or(per2).test(str);
              return pre1.and(per2).test(str);
          }
      }
      
      
    4. Function<T,R>:转换型接口
      R apply(T t):将T类型的参数传递给方法,转换成R类型之后返回。

      package com.jxufe_ldl.class02.supplier;
      
      import java.util.function.Function;
      
      public class FunctionDemo {
          public static void main(String[] args) {
              String str = "林黛玉,18";
              /*convert(str, (String s) -> {
                  return str.split(",")[1];
              }, (String s) -> {
                  return Integer.parseInt(s);
              }, (Integer i) -> {
                  return i + 70;
              });*/
      
              convert(str, s -> str.split(",")[1], Integer::parseInt, i -> i + 70);
      
          }
          private static void convert(String str, Function<String,String> fun1, Function<String, Integer> fun2,
                                      Function<Integer, Integer> fun3) {
              int i = fun1.andThen(fun2).andThen(fun3).apply(str);
      
              System.out.println(i);
          }
      }
      
      

Stream流

  • 概念:Stream流就是一套操作集合的工具集。工具集:指的就是Stream流中已经封装好了很多操作集合的方法,我们当作工具直接用就行了。
  • Stream流操作的对象:单列集合、数组、Map集合(只能间接操作)。
    使用注意事项:Stream流对象只能被使用一次,否则会出现如下异常:
    java.lang.IllegalStateException: stream has already been operated upon or closed
  • Stream流操作的步骤:
    1. 生成Stream流对象
      Stream stream=单列集合对象.stream();
      Stream stream=Stream.of(T… t);
      注意:Map集合必须要先转换成单列集合(keySet()或者entrySet())之后才可以生成Stream流对象。

    2. 调用Stream流对象的方法
      Stream<T> filter​(Predicate predicate):用于对流中的数据进行过滤,需要使用Predicate接口传递过滤条件
      Stream<T> limit​(long maxSize):截取前指定参数个数的数据,返回截取的元素组成的新流
      Stream<T> skip​(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的新流
      static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流
      Stream<T> distinct​():对流中的元素去重(根据Object.equals(Object) )组成的流
      Stream<T> sorted​():返回由此流的元素组成的流,根据自然顺序排序
      Stream<T> sorted​(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序
      Stream<R> map​(Function mapper):将流中的数据转换成另一种类型进行存储,返回新的流对象。
      Function转换型接口中的方法 R apply​(T t)
      void forEach​(Consumer action):遍历消费流中的数据
      long count​():返回此流中的元素个数

    3. 将流中的数据转换成集合
      List listA = streamA.collect(Collectors.toList());
      Set setB = streamB.collect(Collectors.toSet());

package com.jxufe_ldl.class03;

import java.util.ArrayList;
import java.util.stream.Stream;

/*
    现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作:
        1:男演员只要名字为3个字的前三人
        2:女演员只要姓林的,并且不要第一个
        3:把过滤后的男演员姓名和女演员姓名合并到一起
        4:把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
            演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
*/
public class Streamdemo06 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> manList = new ArrayList<String>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");


        ArrayList<String> womanList = new ArrayList<String>();
        womanList.add("林心如");
        womanList.add("张曼玉");
        womanList.add("林青霞");
        womanList.add("柳岩");
        womanList.add("林志玲");
        womanList.add("王祖贤");

        // 1:男演员只要名字为3个字的前三人
        Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);

        // 2:女演员只要姓林的,并且不要第一个
        Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);

        // 3:把过滤后的男演员姓名和女演员姓名合并到一起
        Stream<String> concatStream = Stream.concat(manStream, womanStream);

        // 4:把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
//        concatStream.map(Actor::new).forEach(System.out::println);
        concatStream.map(s -> new Actor(s)).forEach(System.out::println);

    }
}

package com.jxufe_ldl.class03;

import java.util.ArrayList;
import java.util.List;

public class StreamDemo05 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        list.add("123");
        list.add("223");
        list.add("333");
        list.add("444");
        list.add("555");

        // R apply(T t);
        list.stream().map(s -> {
            return Integer.parseInt(s);
        }).forEach(System.out::println);
    }
}

package com.jxufe_ldl.class03;

import java.util.ArrayList;
import java.util.List;

public class StreamDemo04 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        list.add("liuxiaoyu");
        list.add("liudaliang");
        list.add("yumanli");
        list.add("liukun");
        list.add("liuxiaoliang");
        list.add("caixukun");

        // 使用自然排序
        list.stream().sorted().forEach(System.out::println);
        System.out.println("---------");

        // 排序规则为字符串的长度
        list.stream().sorted((s1, s2) -> s1.length() - s2.length()).forEach(System.out::println);
        System.out.println("---------");

        // 长度相同则自然顺序排序
        list.stream().sorted((s1, s2) -> {
            int num = s1.length() - s2.length();
            num = num == 0 ? s1.compareTo(s2) : num;
            return num;
        }).forEach(System.out::println);

    }
}

package com.jxufe_ldl.class03;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/*
    注意:一个流只能被使用一次.
    static Stream concat(Stream a, Stream b) : 是一个静态方法,需要传入两个Stream流对象,返回一个Stream对象
           方法的作用: 把两个Stream流合并成一个Stream
    Stream<T> distinct() :  去重,把Stream流中重复元素去除一个.
 */
public class StreamDemo03 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        list.add("刘小鱼");
        list.add("刘达亮");
        list.add("于曼丽");
        list.add("刘坤");
        list.add("刘小亮");
        list.add("蔡徐坤");

        // 取集合的前4个元素
        Stream<String> streamA = list.stream().limit(4);

        // 跳过前两个元素,取集合后面的元素
        Stream<String> streamB = list.stream().skip(2);

        // 将两个流合并成一个流
        Stream<String> streamC = Stream.concat(streamA, streamB);
//        streamC.forEach(System.out::println);

        // 将两个流合并成一个流,并去掉重复的元素
        Stream<String> streamD = streamC.distinct();
        streamD.forEach(System.out::println);
    }
}

package com.jxufe_ldl.class03;

import java.util.ArrayList;
import java.util.List;

public class StreamDemo02 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        list.add("刘小鱼");
        list.add("刘达亮");
        list.add("于曼丽");
        list.add("刘坤");
        list.add("刘小亮");
        list.add("蔡徐坤");

        // 取前3个元素
        list.stream().limit(3).forEach(System.out::println);
        System.out.println("--------");

        // 跳过前2个元素
        list.stream().skip(2).forEach(System.out::println);
        System.out.println("--------");

        // 跳过前2个元素,再取前3个元素
        list.stream().skip(2).limit(3).forEach(System.out::println);

    }
}

package com.jxufe_ldl.class03;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

public class StreamDemo01 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        list.add("刘小鱼");
        list.add("刘达亮");
        list.add("于曼丽");
        list.add("刘坤");
        list.add("刘小亮");

        // list.stream().filter(s->s.startsWith("刘")).filter(s->s.length() == 3).forEach(System.out::println);
        list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("刘");
            }
        }).filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() == 3;
            }
        }).forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

        list.stream().filter((String s) -> {
                return s.startsWith("刘");
            }
        ).filter((String s) -> {
                return s.length() == 3;
            }
        ).forEach((String s) -> {
                System.out.println(s);
            }
        );
    }
}

package com.jxufe_ldl.class03;

/*
    演员类
 */
public class Actor {
    private String name;

    public Actor(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Actor{" +
                "name='" + name + '\'' +
                '}';
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值