首页 > 技术文章 > Java笔记之 函数式接口、Stream流

coder-ahao 2021-01-02 21:33 原文

函数式接口

函数式接口概述

函数式接口:有且仅有一个抽象方法的接口

Java的函数式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口,只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利的进行推导。

如何检测一个接口是不是函数式接口呢?

@FunctionalInterface,放在接口定义的上方:如果接口是函数式接口,那么编译通过,如果不是,编译失败

自己定义的时候,加不加上这个注解都可以,但是建议加上。

函数式接口作为方法的参数

需求:

定义一个RunnableDemo类,在类中提供两个方法

1.startThread(Runnable r),方法参数Runnable是一个函数式接口。

2.主方法,在主方法中调用startThread方法。

如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递

startThread(()->System.out.println(Thread.currentThread().getName()+"线程启动了"));

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    public class RunnableDemo {
  4.  
    public static void main(String[] args) {
  5.  
    startThread(new Runnable() {
  6.  
    @Override
  7.  
    public void run() {
  8.  
    System.out.println(Thread.currentThread().getName()+"线程启动了");
  9.  
    }
  10.  
    });
  11.  
    }
  12.  
    startThread(()->System.out.println(Thread.currentThread().getName()+"线程启动了"));
  13.  
     
  14.  
    private static void startThread(Runnable r) {
  15.  
    // Thread t = new Thread(r);
  16.  
    // t.start();
  17.  
    new Thread(r).start();
  18.  
    }
  19.  
    }

函数式接口作为方法的返回值

需求:

定义一个ComparatorDemo类,在类中提供两个方法

1.Comparator<String> getComparator(),方法返回值Comparator是一个函数式接口。

2.主方法,在主方法中调用getComparator()方法。

如果方法返回是一个函数式接口,我们可以使用Lambda表达式作为结果返回

private static Comparator<String> getComparator(){

    return (s1,s2)->s1.length()-s2.length();

}

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.ArrayList;
  4.  
    import java.util.Collections;
  5.  
    import java.util.Comparator;
  6.  
     
  7.  
    public class ComparatorDemo {
  8.  
    public static void main(String[] args) {
  9.  
    ArrayList<String> s = new ArrayList<>();
  10.  
    s.add("sss");
  11.  
    s.add("derde");
  12.  
    s.add("asedeff");
  13.  
    s.add("w");
  14.  
    System.out.println(s);
  15.  
    Collections.sort(s);
  16.  
    System.out.println(s);
  17.  
    Collections.sort(s,getComparator());
  18.  
    System.out.println(s);
  19.  
     
  20.  
    }
  21.  
    private static Comparator<String> getComparator(){
  22.  
    //匿名内部类的实现
  23.  
    // Comparator<String> comp = new Comparator<String>() {
  24.  
    // @Override
  25.  
    // public int compare(String s1, String s2) {
  26.  
    // return s1.length()-s2.length();
  27.  
    // }
  28.  
    // };
  29.  
    // return comp;
  30.  
     
  31.  
    // return new Comparator<String>() {
  32.  
    // @Override
  33.  
    // public int compare(String s1, String s2) {
  34.  
    // return s1.length()-s2.length();
  35.  
    // }
  36.  
    // };
  37.  
     
  38.  
    // return (String s1,String s2)->{
  39.  
    // return s1.length()-s2.length();
  40.  
    // };
  41.  
     
  42.  
    return (s1,s2)->s1.length()-s2.length();
  43.  
    }
  44.  
     
  45.  
    }

常用的函数式接口

1.Supplier接口

2.Consumer接口

3.Predicate接口

4.Function接口

Supplier接口

Supplier<T> :包含一个无参的方法

该方法不需要参数,他会按照某种实现逻辑(由Lambda表达式实现)返回一个数据。

Supplier<T> 接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.function.Supplier;
  4.  
     
  5.  
    public class SupplierDemo {
  6.  
    public static void main(String[] args) {
  7.  
    String s = getString(new Supplier<String>() {
  8.  
    @Override
  9.  
    public String get() {
  10.  
    return "zayn";
  11.  
    }
  12.  
    });
  13.  
    System.out.println(s);
  14.  
    String ss = getString(()-> "zayn");
  15.  
    System.out.println(ss);
  16.  
    int x = getInteger(()->22);
  17.  
    System.out.println(x);
  18.  
    }
  19.  
    private static String getString(Supplier<String> sup){
  20.  
    return sup.get();
  21.  
    }
  22.  
    public static Integer getInteger(Supplier<Integer> sup){
  23.  
    return sup.get();
  24.  
    }
  25.  
     
  26.  
    }

Consumer接口

Consumer<T>包含两个方法

1.void accept(T t):对给定的参数执行此操作

2.default Consumer<T> andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作

Consumer<T>接口也被称为消费型接口,他消费的数据的数据类型由泛型指定

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.function.Consumer;
  4.  
     
  5.  
    public class ConsumerDemo {
  6.  
    public static void main(String[] args) {
  7.  
    operateString("hh", new Consumer() {
  8.  
    @Override
  9.  
    public void accept(Object s) {
  10.  
    System.out.println(s);
  11.  
    }
  12.  
    });
  13.  
    operateString("zayn",(s)-> System.out.println(s));
  14.  
    operateString("naill",System.out::println);
  15.  
    operateString("zayn",(s)-> System.out.println(s),(s)-> System.out.println(new StringBuilder(String.valueOf(s)).reverse().toString()));
  16.  
    }
  17.  
    private static void operateString(String s,Consumer con){
  18.  
    con.accept(s);
  19.  
    }
  20.  
    private static void operateString(String s,Consumer con1,Consumer con2){
  21.  
    con1.andThen(con2).accept(s);
  22.  
     
  23.  
    }
  24.  
    }

Predicate接口

Predicate<T>:常用的四个方法

1.boolean test(T t):对于给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。

2.default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非

3.default Predicate<T> and(Predicate other):返回一个组合判断,对应短路与

4.default Predicate<T> or (Predicate other):返回一个组合判断,对应短路或

Predicate<T> 接口通常用于判断参数是否满足指定条件

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.function.Predicate;
  4.  
     
  5.  
    public class PredicateDemo {
  6.  
    public static void main(String[] args) {
  7.  
    //boolean b = checkString("zayn",s-> s.length()>5);
  8.  
    boolean b = checkString("zayn",(String s)->{
  9.  
    return s.length()>5;
  10.  
    });
  11.  
    System.out.println(b);
  12.  
    boolean bb = checkString("zayn",s->s.length()>5,s -> s.length()<10);
  13.  
    System.out.println(bb);
  14.  
     
  15.  
    }
  16.  
    private static boolean checkString(String s, Predicate<String> p){
  17.  
    //return p.test(s);
  18.  
    //return !p.test(s);
  19.  
    return p.negate().test(s);
  20.  
    }
  21.  
    private static boolean checkString(String s, Predicate<String> p1,Predicate<String> p2){
  22.  
    // boolean b1= p1.test(s);
  23.  
    // boolean b2= p2.test(s);
  24.  
    // return b1&&b2;
  25.  
    //return p1.and(p2).test(s);
  26.  
    return p1.or(p2).test(s);
  27.  
    }
  28.  
    }

 Function接口

Function<T,R>:常用的两个方法

1. R apply(T t):将此函数应用于给定的参数

2.default<V> Function andThen(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果

Function<T,R>接口通常用于对参数进行处理、转换(处理逻辑由Lambda表达式实现),然后返回一个新的值

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.function.Function;
  4.  
     
  5.  
    public class FunctionDemo {
  6.  
    public static void main(String[] args) {
  7.  
    convert("100",s->Integer.parseInt(s));
  8.  
    convert("100",Integer::parseInt);
  9.  
    convert(100,i->String.valueOf(i+566));
  10.  
    convert("100",s->Integer.parseInt(s),i->String.valueOf(i+566));
  11.  
    }
  12.  
    //定义一个方法,把一个字符串转换为int类型,在控制台上输出
  13.  
    private static void convert(String s, Function<String,Integer> fun){
  14.  
    int i = fun.apply(s);
  15.  
    System.out.println(i);
  16.  
    }
  17.  
    //定义一个方法,把一个int类型的数据加上一个整数后,转换为字符串进行输出
  18.  
    private static void convert(int i ,Function<Integer,String> fun){
  19.  
    String s = fun.apply(i);
  20.  
    System.out.println(s);
  21.  
    }
  22.  
    //定义一个方法,把一个字符串转换为int类型,把一个int类型的数据加上一个整数后,转换为字符串进行输出
  23.  
    private static void convert(String s,Function<String,Integer> fun1,Function<Integer,String> fun2){
  24.  
    // String ss = fun2.apply(fun1.apply(s));
  25.  
    // System.out.println(ss);
  26.  
    String ss = fun1.andThen(fun2).apply(s);
  27.  
    System.out.println(ss);
  28.  
    }
  29.  
     
  30.  
    }

Stream流

体验Stream流

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.ArrayList;
  4.  
     
  5.  
    public class StreamDemo {
  6.  
    public static void main(String[] args) {
  7.  
    ArrayList<String> list = new ArrayList<>();
  8.  
    list.add("林青霞");
  9.  
    list.add("张曼玉");
  10.  
    list.add("王祖贤");
  11.  
    list.add("柳岩");
  12.  
    list.add("张三");
  13.  
    list.add("张无忌");
  14.  
    list.stream().filter(s->s.length()==3).filter(s -> s.startsWith("张")).forEach(System.out::println);
  15.  
    }
  16.  
    }

Stream流的生成方式

stream流的常见生成方式

1.Collection体系的集合可以使用默认方法stream()生成流    default Stream<E> stream()

2.Map体系的集合间接的生成流

3.数组可以通过Stream接口的静态方法of(T...values)生成流

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.*;
  4.  
    import java.util.stream.Stream;
  5.  
     
  6.  
    public class StreamDemo1 {
  7.  
    public static void main(String[] args) {
  8.  
     
  9.  
    //Collection体系的集合可以使用默认方法stream()生成流 default Stream<E> stream()
  10.  
    List<String> l = new ArrayList<>();
  11.  
    Stream<String> listStream = l.stream();
  12.  
    Set<String> s = new HashSet<>();
  13.  
    Stream<String> setStream = s.stream();
  14.  
     
  15.  
    //Map体系的集合间接的生成流
  16.  
    Map<String,Integer> map = new HashMap<>();
  17.  
    Stream<String> keyStream = map.keySet().stream();
  18.  
    Stream<Integer> valueStream = map.values().stream();
  19.  
    Stream<Map.Entry<String,Integer>> entryStream = map.entrySet().stream();
  20.  
     
  21.  
    //数组可以通过Stream接口的静态方法of(T...values)生成流
  22.  
    String[] strArray = {"hello","java","zayn"};
  23.  
    Stream<String> strArrayStream1 = Stream.of(strArray);
  24.  
    Stream<String> strArrayStream2 = Stream.of("hello","java","zayn");
  25.  
    Stream<Integer>intStream = Stream.of(1,2,3,4,5);
  26.  
    }
  27.  
    }

Stream流中常见的中间操作方法

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.ArrayList;
  4.  
    import java.util.stream.Stream;
  5.  
     
  6.  
    public class StreamDemo2 {
  7.  
    public static void main(String[] args) {
  8.  
    ArrayList<String> list = new ArrayList<>();
  9.  
    list.add("林青霞");
  10.  
    list.add("张曼玉");
  11.  
    list.add("王祖贤");
  12.  
    list.add("柳岩");
  13.  
    list.add("张敏");
  14.  
    list.add("张无忌");
  15.  
     
  16.  
    //需求1:取前3个数据在控制台输出
  17.  
    list.stream().limit(3).forEach(System.out::println);
  18.  
    System.out.println("--------");
  19.  
    //需求2:跳过前三个数据,剩余的数据在控制台输出
  20.  
    list.stream().skip(3).forEach(System.out::println);
  21.  
    System.out.println("--------");
  22.  
    //需求3:跳过前2个数据,取前2个数据在控制台输出
  23.  
    list.stream().skip(2).limit(2).forEach(System.out::println);
  24.  
    System.out.println("--------");
  25.  
    //需求4:取前4个数据组成一个流
  26.  
    Stream<String> s1 = list.stream().limit(4);
  27.  
    System.out.println("--------");
  28.  
    //需求5:跳过2个数据组成一个流
  29.  
    Stream<String> s2 = list.stream().skip(2);
  30.  
    System.out.println("--------");
  31.  
    //需求6:合并需求4和需求5得到一个流,并把结果在控制台上输出
  32.  
    //Stream.concat(s1,s2).forEach(System.out::println);
  33.  
    System.out.println("--------");
  34.  
    //需求7:合并需求4和需求5得到一个流,并把结果在控制台上输出,要求字符串元素不能重复
  35.  
    Stream.concat(s1,s2).distinct().forEach(System.out::println);
  36.  
    System.out.println("--------");
  37.  
    System.out.println("deretfrefewrfgerg");
  38.  
    }
  39.  
    }
  40.  
     
  41.  
    package com.FunctionInterface;
  42.  
     
  43.  
    import java.util.ArrayList;
  44.  
     
  45.  
    public class StreamDemo3 {
  46.  
    public static void main(String[] args) {
  47.  
    ArrayList<String> list = new ArrayList<>();
  48.  
    list.add("defrefrg");
  49.  
    list.add("deffffff");
  50.  
    list.add("cdfref");
  51.  
    list.add("aaa");
  52.  
    list.add("wwwwwwww");
  53.  
    list.add("defferrf");
  54.  
     
  55.  
    //需求1:按照字母顺序把数据在控制台输出
  56.  
    list.stream().sorted().forEach(System.out::println);
  57.  
    System.out.println("--------");
  58.  
    //需求2:按照字符串长度把数据在控制台输出
  59.  
    //list.stream().sorted((s1,s2)->s1.length()-s2.length()).forEach(System.out::println);
  60.  
    list.stream().sorted((s1,s2)->{
  61.  
    int l = s1.length()-s2.length();
  62.  
    int num = l==0?s1.compareTo(s2):l;
  63.  
    return num;
  64.  
    }).forEach(System.out::println);
  65.  
    //需求1:按照字母顺序把数据在控制台输出
  66.  
    }
  67.  
    }
  68.  
     
  69.  
     
  70.  
    package com.FunctionInterface;
  71.  
     
  72.  
    import java.util.ArrayList;
  73.  
     
  74.  
    public class StreamDemo4 {
  75.  
    public static void main(String[] args) {
  76.  
    ArrayList<String> list = new ArrayList<>();
  77.  
    list.add("10");
  78.  
    list.add("20");
  79.  
    list.add("30");
  80.  
    list.add("40");
  81.  
    list.add("50");
  82.  
     
  83.  
    //需求:将集合中的数据转换成整数后在控制台输出
  84.  
    //list.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
  85.  
    list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
  86.  
     
  87.  
    //int sum() 返回此流中元素对总和
  88.  
    int result = list.stream().mapToInt(Integer::parseInt).sum();
  89.  
    System.out.println(result);
  90.  
    }
  91.  
    }
  92.  
     

Stream流中常见的终结方法

1.void forEach(Consumer action):对流的每个元素执行操作,Consumer接口中的方法 void accept(T t):对给定的参数执行此操作

2.long count():返回此流的元素数

  1.  
    package com.FunctionInterface;
  2.  
     
  3.  
    import java.util.ArrayList;
  4.  
     
  5.  
    public class StreamDemo {
  6.  
    public static void main(String[] args) {
  7.  
    ArrayList<String> list = new ArrayList<>();
  8.  
    list.add("林青霞");
  9.  
    list.add("张曼玉");
  10.  
    list.add("王祖贤");
  11.  
    list.add("柳岩");
  12.  
    list.add("张三");
  13.  
    list.add("张无忌");
  14.  
    //list.stream().filter(s->s.length()==3).filter(s -> s.startsWith("张")).forEach(System.out::println);
  15.  
    list.stream().forEach(System.out::println);
  16.  
    System.out.println(list.stream().filter(s -> s.startsWith("张")).count());
  17.  
    }
  18.  
    }

Stream流的收集操作

对数据使用Stream流的方式操作完毕后,我想把流中的数据收集到集合中,怎么办?

Stream流的收集方法

1.R collect(Collector collector)

2.但是这个收集方法的参数是一个collection的接口

工具类Collectors提供了具体的收集方式

1.public static <T> Collector toList():把元素收集到list集合中

2.public static <T> Collector toSet():把元素收集到set集合中

3.public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到map集合中

  1.  
    package com.FunctionInterface;
  2.  
    import java.util.*;
  3.  
    import java.util.stream.Collector;
  4.  
    import java.util.stream.Collectors;
  5.  
    import java.util.stream.Stream;
  6.  
     
  7.  
     
  8.  
    public class CollectionDemo1 {
  9.  
    public static void main(String[] args) {
  10.  
    List<String> list = new ArrayList<>();
  11.  
    list.add("林青霞");
  12.  
    list.add("张曼玉");
  13.  
    list.add("王祖贤");
  14.  
    list.add("柳岩");
  15.  
     
  16.  
    //需求1.得到名字为3个字的流
  17.  
    Stream<String> stream = list.stream().filter(s->s.length()==3);
  18.  
     
  19.  
    //需求2.把stream流操作完毕的数据收集到List集合中并遍历
  20.  
    //List<String> names = stream.collect(Collectors.toList());
  21.  
    Set<String> names = stream.collect(Collectors.toSet());
  22.  
    for(String name:names){
  23.  
    System.out.println(name);
  24.  
    }
  25.  
     
  26.  
    //创建set集合
  27.  
    Set<Integer> set = new HashSet<>();
  28.  
    set.add(10);
  29.  
    set.add(20);
  30.  
    set.add(30);
  31.  
    set.add(40);
  32.  
    set.add(50);
  33.  
     
  34.  
    //需求3.得到年龄大于25的流
  35.  
    Stream<Integer> stream1 = set.stream().filter(i->i>25);
  36.  
     
  37.  
    //需求4.把stream流操作完毕的数据收集到Set集合中并遍历
  38.  
    Set<Integer> s = stream1.collect(Collectors.toSet());
  39.  
    for(int i : s){
  40.  
    System.out.println(i);
  41.  
    }
  42.  
     
  43.  
    //定义一个字符串数组,每一个字符串的数据由姓名和年龄组成
  44.  
    String[] strArray = { "林青霞,30","张曼玉,35","王祖贤,33","柳岩,25"};
  45.  
     
  46.  
    //需求5.得到字符串中年龄大于28的流
  47.  
    Stream<String> stream2 = Stream.of(strArray).filter( ss ->Integer.parseInt(ss.split(",")[1])>28);
  48.  
     
  49.  
    //需求6.把stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名做键,年龄做值
  50.  
    Map<String,Integer> map = stream2.collect(Collectors.toMap(s1->s1.split(",")[0],s2->Integer.parseInt(s2.split(",")[1])));
  51.  
    Set<String> keySet = map.keySet();
  52.  
    for(String key :keySet){
  53.  
    System.out.println(key+":"+map.get(key));
  54.  
    }
  55.  
    }
  56.  
    }

 

推荐阅读