函数式接口

函数式接口

1.概述

1.1 定义

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

Java中的函数式接口体现就是Lambda表达式,所以函数式接口就是可以使用Lambda表达式的接口

只有确保接口中有且仅有一个抽象方法,Java中Lambda表达式才能顺利进行推导

1.2 使用

如何检测一个接口是否为函数式接口?

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

注意:

  1. 我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要满足函数式接口定义的条件,也同样是函数式接口。但是,建议加上该注解
//函数式接口:有且仅有一个抽象方法的接口
public class MyInterfaceDemo {
    public static void main(String[] args) {
        MyInterface my = () -> System.out.println("函数式接口");
        my.show();//函数式接口
    }
}

@FunctionalInterface
interface MyInterface {
    void show();
//    void test();
}

2.函数式接口作为参数

需求:

  1. 定义一个类(RunnableDemo),在类中提供两个方法
    1. 一个方法是:startThread(Runnable r) 方法参数Runnable是一个函数式接口
    2. 一个是主方法,在主方法中调用startThread方法
public class RunnableDemo {
    public static void main(String[] args) {
        //在主方法中调用startThread方法
        //匿名内部类
        startThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程启动了");
            }
        });
        //Lambda表达式
        startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));
    }

    private static void startThread(Runnable r) {
//        Thread t = new Thread(r);
//        t.start();
        new Thread(r).start();
    }
}

通过上面练习,我们知道:

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

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

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

需求:

  1. 定义一个类(ComparatorDemo),在类中提供两个方法
    1. 一个方法是:Comparator getComparator() 方法返回值Comparator是一个函数式接口
    2. 一个是主方法,在主方法中调用getComparator()方法
package com.advanced.functionalinterface.demo03;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class ComparatorDemo {
    public static void main(String[] args) {
        //构造场景
        ArrayList<String> arr = new ArrayList<String>();

        //向集合中添加元素
        arr.add("cccc");
        arr.add("bb");
        arr.add("aaa");
        arr.add("d");

        //排序前
        System.out.println("排序前:"+arr);//排序前:[cccc, bb, aaa, d]

        //使用工具类自然排序
//        Collections.sort(arr);//排序后:[aaa, bb, cccc, d]
        //使用自定义比较器排序
        Collections.sort(arr,getComparator());//排序后:[d, bb, aaa, cccc]

        //排序后
        System.out.println("排序后:"+arr);
    }

    private static Comparator<String> getComparator() {
        //匿名内部类
//        return new Comparator<String>() {
//            @Override
//            public int compare(String s1, String s2) {
//                return s1.length()-s2.length();
//            }
//        };

        //Lambda表达式
//        return (String s1,String s2) -> {
//            return s1.length()-s2.length();
//        };

        //Lambda简化式
        return (s1,s2) -> s1.length()-s2.length();
    }
}

通过上面练习,我们知道:

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

  • private static Comparator<String> getComparator() {
        return (s1,s2) -> s1.length()-s2.length();
    }
    

4.常用的函数式接口

4.1 内容

Java8在java.util.function包下预定义了大量的函数式接口供我们使用

我们重点学习下面的4个接口:

  1. Supplier接口
  2. Consumer接口
  3. Predicate接口
  4. Function接口

4.2 Supplier接口

  • public interface Supplier:包含一个无参的方法
  • T get():获得结果
  • 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
  • Supplier接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
package com.advanced.functionalinterface.demo04supplier;

import java.util.function.Supplier;

public class SupplierDemo {
    public static void main(String[] args) {
        String s = getString(() -> "林青霞");
        System.out.println(s);

        Integer i = getInteger(() -> 30);
        System.out.println(i);
    }
    
    private static Integer getInteger(Supplier<Integer> i) {
        return i.get();
    }

    private static String getString(Supplier<String> supp) {
        return supp.get();
    }
}

练习:

  1. 定义一个类(SupplierTest),在类中提供两个方法
  2. 一个方法是int getMax(Supplier sup) 返回int数组中的最大值
  3. 一个是主方法,在主方法中调用getMax方法
package com.advanced.functionalinterface.demo04supplier;

import java.util.function.Supplier;

public class SupplierTest {
    public static void main(String[] args) {
        //定义一个int[]数组
        int[] arr = {10, 90, 30, 40, 20, 50};
        int max = getMax(() -> {
            int oldmax = arr[0];
            for (int i = 0; i < arr.length; i++) {
                if (oldmax < arr[i]) {
                    oldmax = arr[i];
                }
            }
            return oldmax;
        });
        System.out.println(max);
    }

    //返回int数组中的最大值
    public static int getMax(Supplier<Integer> sup) {
        return sup.get();
    }
}

4.3 Consumer接口

  • public interface Consumer:包含两个方法
  • void accept(T t): 对给定的参数执行此操作
  • default Consumer andThen(Consumer<? super T> after):返回一个组合的Consumer,按顺序执行该操作,然后执行after操作
  • Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
package com.advanced.functionalinterface.demo05consumer;

import java.util.function.Consumer;

public class ConsumerDemo {
    public static void main(String[] args) {
//        operatorString((s) -> {
//            System.out.println(s);
//        });
        operatorString(s -> System.out.println(s));//林青霞
//        operatorString(System.out::println);

        operatorString(s -> System.out.println(new StringBuilder(s).reverse().toString()));//霞青林

        System.out.println("==========");

        operatorString("林青霞",s -> System.out.println(s),s -> System.out.println(new StringBuilder(s).reverse().toString()));
    }

    //定义一个方法,用不同的方式消费同一个字符串两次
    public static void operatorString(String name,Consumer<String> con1,Consumer<String> con2) {
//        con1.accept(name);
//        con2.accept(name);
        con1.andThen(con2).accept(name);
    }

    //定义一个方法,消费一个字符串数据
    public static void operatorString(Consumer<String> con) {
        con.accept("林青霞");
    }
}

练习:

  1. String[] strArray = {“林青霞,30”,“张曼玉,35”,“王祖贤,33”};
  2. 字符串数组中的多条信息,请按格式:“姓名:XX,年龄:XX”的格式信息打印出来
  3. 要求:
    1. 把打印姓名的动作作为第一个Consumer接口的Lambda实例
    2. 把打印年龄的动作作为第二个Consumer接口的Lambda实例
    3. 将两个Consumer接口按顺序组合在一起使用
package com.advanced.functionalinterface.demo05consumer;

import java.util.function.Consumer;

public class ConsumerTest {
    public static void main(String[] args) {
        //定义一个字符串数组
        String[] strArray = {"林青霞,30","张曼玉,35","王祖贤,33"};

        //拆分字符串数组并打印
        for (int i = 0; i < strArray.length; i++) {
            String[] s = strArray[i].split(",");
            //将年龄从String类型转换为Integer类型
            String name = s[0];
            int age = Integer.parseInt(s[1]);
            printInfo(name,age,(s1) -> System.out.print("姓名:"+name),(i1)-> System.out.println(", 年龄:"+age));
        }
    }

    //定义一个方法,按指定格式打印字符串数组
    private static void printInfo(String name, Integer age, Consumer<String> con1,Consumer<Integer> con2) {
        con1.accept(name);
        con2.accept(age);
    }
}

优化代码:

package com.advanced.functionalinterface.demo05consumer;

import java.util.function.Consumer;

public class ConsumerTest02 {
    public static void main(String[] args) {
        String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33"};

//        printInfo(strArray, (arr) -> {
//            String name = arr.split(",")[0];
//            System.out.print("姓名:" + name);
//        }, (arr) -> {
//            int age = Integer.parseInt(arr.split(",")[1]);
//            System.out.println(", 年龄:" + age);
//        });

        //简化上面代码
        printInfo(strArray, str -> System.out.print("姓名:" + str.split(",")[0]),
                str -> System.out.println(", 年龄:" + Integer.parseInt(str.split(",")[1])));
    }

    private static void printInfo(String[] arrays, Consumer<String> con1, Consumer<String> con2) {
        for (String arr : arrays) {
            con1.andThen(con2).accept(arr);
        }
    }
}

4.4 Predicate接口

Predicate:常用的四个方法:

  1. boolean test(T t):在给定的参数上评估这个谓词(判断逻辑由Lambda表达式实现),返回一个布尔值
  2. default Predicate negate():返回一个逻辑的否定,对应逻辑非
  3. default Predicate and(Predicate<? super T> other):返回一个组合判断,对用短路与
  4. default Predicate or(Predicate<? super T> other):返回一个组合判断,对应短路或
  5. Predicate接口常用于判断参数是否满足指定的条件

test与negate方法:

package com.advanced.functionalinterface.demo06predicate;

import java.util.function.Predicate;

public class PredicateDemo01 {
    public static void main(String[] args) {
//        boolean b1 = checkString("hello", (s) -> {
//            return s.length()>8;
//        });
        boolean b1 = checkString("hello", s -> s.length() > 8);
        System.out.println(b1);//false

        boolean b2 = checkString("helloworld", s -> s.length() > 8);
        System.out.println(b2);//true
    }

    //判断给定的字符串是否满足要求
    private static boolean checkString(String s, Predicate<String> pre) {
        return pre.test(s);//在给定的参数上评估这个谓词(判断逻辑由Lambda表达式实现),返回一个布尔值
//        return !pre.test(s);
//        return pre.negate().test(s);//default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非
    }
}

and与or方法:

package com.advanced.functionalinterface.demo06predicate;

import java.util.function.Predicate;

public class PredicateDemo02 {
    public static void main(String[] args) {
        boolean b1 = checkString("hello", s -> s.length() > 8);
        System.out.println(b1);

        boolean b2 = checkString("helloworld", s -> s.length() > 8);
        System.out.println(b2);

        boolean b3 = checkString("hello", s -> s.length() > 8, s -> s.length() < 15);
        System.out.println(b3);

        boolean b4 = checkString("helloworld", s -> s.length() > 8, s -> s.length() < 15);
        System.out.println(b4);
    }

    //同一个字符串给出两种不同的判断,并将两个判断结果做逻辑与所得的结果作为最终结果
    private static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) {
//        boolean b1 = pre1.test(s);
//        boolean b2 = pre2.test(s);
//        boolean b = b1 && b2;
//        return b;
//        return pre1.and(pre2).test(s);//短路与(逻辑与)
        return pre1.or(pre2).test(s);//短路或(逻辑或)
    }

    //判断给定的字符串是否满足要求
    private static boolean checkString(String s, Predicate<String> pre) {
        return pre.test(s);
    }
}

练习:

  1. String[] strArray = {“林青霞,30”,“柳岩,34”,“张曼玉,35”,“貂蝉,31”,“王祖贤,33”};
  2. 字符串数组中由多条信息,请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历集合
  3. 同时满足以下要求:姓名长度大于2,年龄大于33
package com.advanced.functionalinterface.demo06predicate;

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

public class PredicateTest {
    public static void main(String[] args) {
        //定义字符串数组
        String[] strArray = {"林青霞,30","柳岩,34","张曼玉,35","貂蝉,31","王祖贤,33"};

        boolean b = checkString(strArray,s -> s.split(",")[0].length()>2,
                s -> Integer.parseInt(s.split(",")[1])>33);

    }

    //通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历集合
    private static boolean checkString(String[] arrays, Predicate<String> pre1, Predicate<String> pre2) {
        ArrayList<String> list2 = new ArrayList<String>();
        boolean b = false;
        for (String s: arrays) {
            b = pre1.and(pre2).test(s);
            if (b) {
                list2.add(s);
            }
        }
        for (String s : list2) {
            System.out.println(s);
        }
        return b;
    }
}

改进后:

package com.advanced.functionalinterface.demo06predicate;

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

public class PredicateTest02 {
    public static void main(String[] args) {
        //定义字符串数组
        String[] strArray = {"林青霞,30","柳岩,34","张曼玉,35","貂蝉,31","王祖贤,33"};

        ArrayList<String> array = checkString(strArray, s -> s.split(",")[0].length() > 2,
                s -> Integer.parseInt(s.split(",")[1]) > 33);

        //遍历集合
        for (String s : array) {
            System.out.println(s);
        }
    }

    //通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList
    private static ArrayList<String> checkString(String[] arrays, Predicate<String> pre1, Predicate<String> pre2) {
        //创建集合对象
        ArrayList<String> list = new ArrayList<String>();

        //遍历字符串数组
        for (String str : arrays) {
            if (pre1.and(pre2).test(str)) {
                list.add(str);
            }
        }

        return list;
    }
}

4.5 Function接口

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

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

  2. default Function<T,V> andThen(Function<? super R,? extends V> after):

    返回一个组合函数,首先将此函数应用于其输入,然后将after函数应用于结果

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

package com.advanced.functionalinterface.demo07function;

import java.util.function.Function;

public class FunctionDemo {
    public static void main(String[] args) {
        convert("100", s -> Integer.parseInt(s));

        convert(100, i -> String.valueOf(i + 566));

        convert("100", s -> Integer.parseInt(s), i -> String.valueOf(i + 566));
    }

    //定义一个方法,把字符串转为int类型,在控制台输出
    private static void convert(String s, Function<String, Integer> fun) {
        Integer i = fun.apply(s);
        System.out.println(i);
    }

    //定义一个方法,把int类型数据加一个整数后,转换为字符串在控制台输出
    private static void convert(int i, Function<Integer, String> fun) {
        String s = fun.apply(i);
        System.out.println(s);
    }

    //定义一个方法,把字符串转为int类型,在加一个整数后,重新转为字符串在控制台输出
    private static void convert(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
//        int i = fun1.apply(s);
//        String ss = fun2.apply(i);
//        System.out.println(ss);

        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }
}

练习:

  1. String s = “林青霞,30”;
  2. 请按照指定要求进行操作:
    1. 将字符串截取得到年龄部分
    2. 将上一步得到的年龄字符串转为int类型
    3. 将上一步int类型数据加70,得到一个int结果,在控制台输出
  3. 通过Function接口来实现函数拼接
package com.advanced.functionalinterface.demo07function;

import java.util.function.Function;

public class FunctionTest {
    public static void main(String[] args) {
        //定义一个字符串
        String s = "林青霞,30";

        convert(s, s1 -> Integer.parseInt(s.split(",")[1]), i -> i + 70);
    }

    //通过Function接口来实现函数拼接
    private static void convert(String s, Function<String, Integer> fun1, Function<Integer, Integer> fun2) {
        Integer age = fun1.andThen(fun2).apply(s);
        System.out.println(age);
    }
}

5. Stream流

5.1 体验Stream流

需求:按照下面要求完成集合创建和遍历

  1. 创建一个集合,存储多个字符串元素
  2. 把集合中所有姓张的元素存储到新集合
  3. 把张开头长度为3的元素存储到新集合
  4. 遍历上一步得到的集合
package com.advanced.stream.demo01;

import java.util.ArrayList;

public class StreamDemo {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("张无忌");
        list.add("张敏");

        //张开头的集合
        ArrayList<String> zhanglist = new ArrayList<>();

        //遍历集合
        for (String s : list) {
             if (s.startsWith("张")) {
                 zhanglist.add(s);
             }
        }
//        System.out.println(zhanglist);//[张曼玉, 张无忌, 张敏]

        //长度为3的集合
        ArrayList<String> threeList = new ArrayList<>();
        for (String s : zhanglist) {
            if (s.length() == 3) {
                threeList.add(s);
            }
        }
//        System.out.println(threeList);//[张曼玉, 张无忌]

        for (String s : threeList) {
            System.out.println(s);
        }

        System.out.println("==========\\(@_@)/==========");

        //使用Stream流改进
//        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
    }
}

使用wanstream流的方式完成过滤操作

  1. list.stream().filter(s -> s.startsWith(“张”)).filter(s -> s.length() == 3).forEach(System.out::println);
  2. 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:生成流、过滤姓张、过滤长度为3、逐一打印
  3. stream流把真正的函数式编程风格引入到Java中

5.2 Stream流生成方式

Stream流的使用

  1. 生成流

    通过数据源(集合、数组等)生成流

    list.stream()

  2. 中间操作

    一个流后面可以跟随一个或多个中间操作,其主要目的是打开流,做出某种程度的过滤/映射,然后返回一个新的流,交给下一个操作使用

    filter()

  3. 终结操作

    一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作

    forEach()

Stream流常见生成方式

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

    default Stream stream()

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

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

package com.advanced.stream.demo02;

import java.util.*;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
        //Collection体系的集合可以使用默认方法stream()生成流
        List<String> list = new ArrayList<>();
        Stream<String> listStream = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> setStream = set.stream();

        //Map体系的集合间接生成流
        Map<String,Integer> map = new HashMap<>();
        Stream<String> keyStream = map.keySet().stream();//通过键生成stream流
        Stream<Integer> valueStream = map.values().stream();//通过值生成stream流
        Set<Map.Entry<String, Integer>> entryStream = map.entrySet();//通过键值对生成stream流
        
        //数组可以通过Stream接口的静态方法of(T...values)生成流
        String s = "hello";
        Stream<String> strStream = Stream.of(s);
        Stream<String> strArraysStream = Stream.of("hello", "world", "java");
        Stream<Integer> intStream = Stream.of(10, 20, 30);
    }
}

5.3 Stream流常见中间操作方式

  • Stream filter(Predicate<? super T> predicate):返回由与此给定谓词匹配的此流的元素组成的流,用于对流中数据进行过滤
    • predicate接口中的方法 boolean test(T t):对给定参数进行判断,返回一个布尔值
package com.advanced.stream.demo03;

import java.util.ArrayList;

public class StreamDemo01 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("张无忌");
        list.add("张敏");

        //需求1:把list集合中以张开头元素在控制台打印
        list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
        System.out.println("==========");

        //需求2:把list集合中长度为3的元素在控制台打印
        list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
        System.out.println("==========");

        //需求3:把list集合中以张开头,长度为3元素在控制台打印
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
    }
}
  • Stream limit(long maxSize):返回由此流的元素组成的流,截取指定个数的数据,截短长度不能超过 maxSize
  • Stream skip(long n):跳过指定参数个数的数据,返回由该流剩余元素组成的流
package com.advanced.stream.demo03;

import java.util.ArrayList;

public class StreamDemo02 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("张无忌");
        list.add("张敏");

        //需求1:取前3个元素在控制台输出
        list.stream().limit(3).forEach(System.out::println);
        System.out.println("----------");

        //需求2:跳过前3个元素,将剩余的元素在控制台输出
        list.stream().skip(3).forEach(System.out::println);
        System.out.println("----------");

        //需求3:跳过前2个元素,将剩余的元素的前2个在控制台输出
        list.stream().skip(2).limit(2).forEach(System.out::println);
    }
}
  • static Stream concat(Stream<? extends T> a, Stream<? extends T> b):创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。即合并a和b两个流为一个流
  • Stream distinct():返回由该流的不同元素(根据 Object.equals(Object))组成的流
package com.advanced.stream.demo03;

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

public class StreamDemo03 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("张无忌");
        list.add("张敏");

        //需求1:取前4个元素形成一个流
        Stream<String> stream1 = list.stream().limit(4);

        //需求2:跳过前2个元素形成一个流
        Stream<String> stream2 = list.stream().skip(2);

        //需求3:合并需求1和需求2的流,并将结果在控制台输出
//        Stream.concat(stream1,stream2).forEach(System.out::println);

        //需求4:合并需求1和需求2的流,并将结果在控制台输出,要求不能有重复元素
        Stream.concat(stream1,stream2).distinct().forEach(System.out::println);
    }
}
  • Streamsorted():返回由此流的元素组成的流,根据自然顺序排序
  • Stream sorted(Comparator<? super T> comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序
package com.advanced.stream.demo03;

import java.util.ArrayList;

public class StreamDemo04 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<>();

        list.add("linqingxia");
        list.add("zhangmanyu");
        list.add("wangzuxian");
        list.add("liuyan");
        list.add("zhangmin");
        list.add("zhangwuji");

        //需求1:按照字母顺序在控制台输出
//        list.stream().sorted().forEach(System.out::println);

        //需求2:按照字符串长度把数据在控制台输出
//        list.stream().sorted((s1,s2) -> s1.length()-s2.length()).forEach(System.out::println);
        list.stream().sorted((s1,s2) -> {
            int num1 = s1.length() - s2.length();
            int num2 = num1 == 0 ? s1.compareTo(s2) : num1;
            return num2;
        }).forEach(System.out::println);
    }
}
  • Stream map(Function<? super T,? extends R> mapper):返回由给定函数应用于此流的元素的结果组成的流
    Function接口中方法 R apply(T t)

  • IntStream mapToInt(ToIntFunction<? super T> mapper):返回一个 IntStream,其中包含将给定函数应用于此流的元素的结果
    IntStream:表示原始int流
    ToIntFunction接口中方法 int applyAsInt(T value)

package com.advanced.stream.demo03;

import java.util.ArrayList;

public class StreamDemo05 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<>();

        list.add("10");
        list.add("20");
        list.add("30");
        list.add("40");
        list.add("50");

        //需求:将集合中字符串数据转换为整数后在控制台输出
//        list.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
//        list.stream().map(Integer::parseInt).forEach(System.out::println);

//        list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);

        //IntStream接口中方法 int sum():返回此流中元素的总和
        int result = list.stream().mapToInt(Integer::parseInt).sum();
        System.out.println(result);//150
    }
} 

5.4 Stream流常见终结操作方法

Stream流常见终结操作方法:

  1. void forEach(Consumer<? super T> action):对此流的每个元素执行操作
    1. Consumer接口中方法 void accept(T t): 对给定的参数执行此操作
  2. long count():返回此流中的元素数
package com.advanced.stream.demo04;

import java.util.ArrayList;

public class StreamDemo {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("张无忌");
        list.add("张敏");

        //需求1:将集合元素在控制台输出
        list.stream().forEach(System.out::println);

        //需求2:统计集合中以‘张’开头的元素个数,并将统计的数在控制台输出
        long count = list.stream().filter(s -> s.startsWith("张")).count();
        System.out.println(count);//3
    }
}

5.5 Stream流练习

现在两个ArrayList集合分别存储6名男演员和6名女演员,要求完成如下操作:

  1. 男演员只要名字长度为3的前3名
  2. 女演员只要姓林的,并且不要第一个
  3. 把过滤后的男演员和女演员姓名结合到一起
  4. 把上一步操作后的元素作为构造方法的参数创建对象,遍历数据
    1. 演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
package com.advanced.stream.demo05;

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

public class StreamTest {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> manList = new ArrayList<>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");

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

        //男演员只要名字长度为3的前3名
        Stream<String> man = manList.stream().filter(s -> s.length() == 3).limit(3);

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

        //把过滤后的男演员和女演员姓名结合到一起
        Stream<String> actor = Stream.concat(man, woman);

        //把上一步操作后的元素作为构造方法的参数创建对象,遍历数据
//        actor.forEach(s -> {
//            Actor a = new Actor(s);
//            System.out.println(a.getName());
//        });

//        actor.forEach(s -> System.out.println(new Actor(s).getName()));
        actor.map(Actor::new).forEach(p -> System.out.println(p.getName()));
    }
}

输出结果:

周润发
刘德华
周星驰
林青霞
林志玲

5.6 Stream流收集操作

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

Stream流收集操作:

  1. R collect(Collector collector)
  2. 但这个收集方法参数是一个Conllector接口

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

  1. public static Collector<T,?,List> toList():返回一个Collector,它将输入元素收集到一个新的List集合
  2. public static Collector<T,?,List> toSet():返回一个Collector,它将输入元素收集到一个新的Set集合
  3. public static Collector<T,?,Map<K,U>> toMap(Function keyMapper,Function valueMapper):返回一个Collector,它将元素累加到一个Map集合,其键和值是将所提供的映射函数应用于输入元素的结果
package com.advanced.stream.demo06;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
        //创建List集合对象
        List<String> list = new ArrayList<>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
/*
        //需求1:得到名字长度为3的流
        Stream<String> listStream = list.stream().filter(s -> s.length() == 3);

        //需求2:把使用Stream流操作完毕的数据收集到List集合并遍历
        List<String> names = listStream.collect(Collectors.toList());
        for (String name : names) {
            System.out.println(name);
        }
*/

        //创建Set集合对象
        Set<Integer> set = new HashSet<>();
        set.add(10);
        set.add(20);
        set.add(30);
        set.add(35);
        set.add(33);

/*
        //需求3:得到年龄大于25的流
        Stream<Integer> setStream = set.stream().filter(age -> age > 25);

        //需求4:把使用Stream流操作完毕的数据收集到Set集合并遍历
        Set<Integer> ages = setStream.collect(Collectors.toSet());
        for (Integer age : ages) {
            System.out.println(age);
        }
*/

        //定义一个字符串数组,每个数据由姓名和年龄组成
        String[] strArrays = {"林青霞,30","张曼玉,35","王祖贤,33","柳岩,25"};

        //需求5:得到字符串数组中年龄大于28的流
        Stream<String> arrStream = Arrays.stream(strArrays).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);

        //需求6:把使用Stream流操作完毕的数据收集到Map集合并遍历,字符串姓名作键,年龄作值
        Map<String, Integer> map = arrStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            Integer value = map.get(key);
            System.out.println(key+","+value);
        }
    }
}
已标记关键词 清除标记
相关推荐
<p> <b><span style="background-color:#FFE500;">【超实用课程内容】</span></b> </p> <p> <br /> </p> <p> <br /> </p> <p> 本课程内容包含讲解<span>解读Nginx的基础知识,</span><span>解读Nginx的核心知识、带领学员进行</span>高并发环境下的Nginx性能优化实战,让学生能够快速将所学融合到企业应用中。 </p> <p> <br /> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><br /> </b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><span style="background-color:#FFE500;">【课程如何观看?】</span></b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> PC端:<a href="https://edu.csdn.net/course/detail/26277"><span id="__kindeditor_bookmark_start_21__"></span></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 移动端:CSDN 学院APP(注意不是CSDN APP哦) </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 本课程为录播课,课程永久有效观看时长,大家可以抓紧时间学习后一起讨论哦~ </p> <p style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <br /> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <strong><span style="background-color:#FFE500;">【学员专享增值服务】</span></strong> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b>源码开放</b> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化 </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 下载方:电脑登录<a href="https://edu.csdn.net/course/detail/26277"></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a>,播放页面右侧点击课件进行资料打包下载 </p> <p> <br /> </p> <p> <br /> </p> <p> <br /> </p>
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页