Hefery 的个人网站

Hefery's Personal Website

Contact:hefery@126.com
  menu
73 文章
0 浏览
4 当前访客
ღゝ◡╹)ノ❤️

Java基础—Lambda+Stream

函数式接口

函数式接口简介

定义:有且仅有一个抽象方法的接口

@FunctionalInterface注解:可以检测接口是否是函数式接口,不是函数式接口无法通过编译

@FunctionalInterface
public interface HeferyFunctionalInterface {
    // 定义抽象方法
    public abstract void method();
}

使用:一般可以作为方法的参数和返回值类型

public class FunctionalInterfaceDemo {

    // 声明方法,参数使用函数式接口 HeferyFunctionalInterface
    public static void show(HeferyFunctionalInterface heferyFunctionalInterface) {
        heferyFunctionalInterface.method();
    }

    public static void main(String[] args) {
        // 调用 show() 方法,方法参数是接口,可以传递接口的匿名内部类
        show(new HeferyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("使用 匿名内部类 重写接口中的抽象方法");
            }
        });

        // 调用 show() 方法,方法参数是函数式接口,可以使用Lambda表达式
        show( ()->{
            System.out.println("使用 Lambda表达式 重写接口中的抽象方法");
        });
    }

}

方法引用

指向静态方法的方法引用

/**
 * (args) -> ClassName.staticMethod(args)
 * ClassName::staticMethod
 */
public void test1() {
    Consumer<String> consumer1 = (String number) -> Integer.parseInt(number);
    Consumer<String> consumer2 = Integer::parseInt;
}

指向任意类型实例方法的方法引用

/**
 * (args) -> args.instanceMethod()
 * ClassName::instanceMethod
 */
public void test2() {
    Consumer<String> consumer1 = (String str) -> str.length();
    Consumer<String> consumer2 = String::length
}

指向现有对象的实例方法的方法引用

/**
 * (args) -> object.instanceMethod(args)
 * object::instanceMethod
 */
public void test3() {
    StringBuilder stringBuilder = new StringBuilder();
    Consumer<String> consumer1 = (String str) -> stringBuilder.append(str);
    Consumer<String> consumer2 = stringBuilder::append
}

常用函数接口

Supplier

生产型接口,获取一个泛型参数指定类型的一对象数据

@FunctionalInterface
public interface Supplier<T> {
    T get();
}
public class SupplierDemo {

    // 需求:求出数组最大值:定义一个方法,方法的参数传递 SuppLier<T)接口
    public static int getListMax(Supplier<Integer> sup) {
        return sup.get();
    }

    public static void main(String[] args) {
        int[] array = {1, 34, 56, 78, 3, 545, 43};
        // 调用 getListMax() 方法,方法的参数 SuppLier 是一个函数式接口,所以可以传递Lambda表达式
        int max = getListMax( () -> {
            int maxValue = array[0];
            for (int i : array) {
                if (maxValue < i) {
                    maxValue = i;
                }
            }
            return maxValue;
        });
        System.out.println(max);  // 545
    }

}

Consumer

消费型接口,泛型执行什么类型,就可以使用 accept 方法消费什么类型的数据(用于接收一个对象进行处理但没有返回)

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
public class ConsumerDemo {

    // 需求:求出数组最大值:定义一个方法,方法的参数传递 SuppLier<T)接口
    public static void consumerMethod(String name, Consumer<String> con) {
        con.accept(name);
    }

    // 需求:需要两个consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
    public static void consumerAndThen(String name, Consumer<String> con1, Consumer<String> con2) {
        /*con1.accept(name);
        con2.accept(name);*/
        con1.andThen(con2).accept(name);  // 谁写前边谁先消费
    }

    public static void main(String[] args) {
        consumerMethod("hefery", (name) -> {
            // 消费字符串:反转
            String reName = new StringBuilder(name).reverse().toString();
            System.out.println(reName);  // yrefeh
        });

        consumerAndThen("hefery",
                (name) -> {
                    // 大写输出
                    System.out.println(name.toUpperCase());  // HEFERY
                },
                (name) -> {
                    // 小写输出
                    System.out.println(name.toLowerCase());  // hefery
                }
        );
    }

}

Predicate

对某种类型的数据进行判断,从而得到一个boolean值结果

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);

    /** && */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /** ! */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /** || */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}
public class PredicateDemo {

    // 判断字符串:长度是否大于5,满足返回true
    public static boolean checkString(String str, Predicate<String> predicate) {
        return predicate.test(str);
    }

    // 判断字符串:长度是否大于5 and 包含H
    public static boolean checkStringAnd(String str, Predicate<String> predicate1, Predicate<String> predicate2) {
        //return predicate1.test(str) && predicate2.test(str);
        return predicate1.and(predicate2).test(str);
    }

    // 判断字符串:长度是否大于5 or 包含H
    public static boolean checkStringOr(String str, Predicate<String> predicate1, Predicate<String> predicate2) {
        //return predicate1.test(str) || predicate2.test(str);
        return predicate1.or(predicate2).test(str);
    }

    // 判断字符串:长度是否大于5,满足返回false
    public static boolean checkStringNegate(String str, Predicate<String> predicate) {
        //return !predicate.test(str);
        return predicate.negate().test(str);
    }

    public static void main(String[] args) {
        String hefery = "hefery";

        // 调用 checkString 方法对字符串进行校验,参数传递字符串和Lambda表达式
        boolean b1 = checkString(hefery, (String str) -> {
            return str.length() > 5;
        });

        boolean b2 = checkString(hefery, str -> str.length() > 5);
        System.out.println(b1);   // true
        System.out.println(b2);  // true

        // 调用 checkStringAnd 方法对字符串进行校验,参数传递字符串和Lambda表达式
        boolean b3 = checkStringAnd(hefery,
                (String str) -> {return str.length() > 5;},
                (String str) -> {return str.contains("H");}
        );
        System.out.println(b3);  // false

        // 调用 checkStringOr 方法对字符串进行校验,参数传递字符串和Lambda表达式
        boolean b4 = checkStringOr(hefery,
                (String str) -> {return str.length() > 5;},
                (String str) -> {return str.contains("H");}
        );
        System.out.println(b4);  // true

        // 调用 checkStringNegate 方法对字符串进行校验,参数传递字符串和Lambda表达式
        boolean b5 = checkStringNegate(hefery, (String str) -> {
            return str.length() > 5;
        });
        System.out.println(b5);  // false
    }

}

Function

转换一个对象为不同类型的对象

@FunctionalInterface
public interface Function<T, R> {
    /** */
    R apply(T t);

    /** */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /** */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /** */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
public class FunctionDemo {

    // 把字符串类型的整数转换为 Integer 类型的整数
    public static void change(String str, Function<String, Integer> function) {
        Integer apply = function.apply(str);
        if (apply instanceof Integer) {
            System.out.println(apply);  // 1234
        }
    }

    // 需求:把string类型的“1234",转换为Inteter类型,把转换后的结果加10,把增加之后的Integer类型的数据,转换为String类型
    public static void changeAndThen(String str, Function<String, Integer> function1, Function<Integer, String> function2) {
        String ss = function1.andThen(function2).apply(str);
        if (ss instanceof String) {
            System.out.println(ss);  // 1244
        }
    }

    public static void main(String[] args) {
        String str = "1234";

        // 调用 change 方法,传递字符串类型的整数和Lambdo表达式
        change(str, (String string) -> {
            return Integer.parseInt(string);
        });
        change(str, string -> Integer.parseInt(string) );

        // 调用 changeandThen 方法,传递字符串类型的整数和Lambdo表达式
        changeAndThen(str,
                //(String string) -> { return Integer.parseInt(string) + 10; },
                string -> Integer.parseInt(string) + 10,
                //(Integer integer) -> { return integer + ""; }
                integer -> integer + ""
        );
    }

}

Lambda

Lambda简介

JDK1.8 引入函数式编程风格,通过行为参数化传递代码。

Lambda使用

Lambda语法

形式:

  • (parameters) -> expression
  • (parameters) -> {statement;}+ 没有参数:() -> System. out. println("Hello World!");

参数:

  • 单个参数:name -> System. out. println("Hello World from"+name+"!");
  • 没有参数,逻辑复杂:() ->{ System.out.println("Hello"); System.out.println("World"); }
  • 两个参数
    BinaryOperator functionAdd = (x,y) -> x+y;
    Long result = functionAdd. apply(1L,2L);
  • 参数显示声明
    BinaryOperatorfunctionAdd = (Long x, Long y) -> x+y;
    Long result = functionAdd. apply(1L, 2L);
// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

使用Lambda作为参数

Java中的Lambda表达式可以被当作是匿名内部类的替代品。如果方法的参数是一个函数式接口类型,那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数,其实就是使用函数式接口作为方法参数

java.lang.Runnable 接口就是一个函数式接口,假设有一个 startThread 方法使用该接口作为参数,那么就可以使用 Lambda 进行传参。这种情况其实和 Thread 类的构造方法参数为 Runnable 没有本质区别

public class RunnableDemo {

    // 定义 startThread() 方法参数使用函数式接口
    public static void startThread(Runnable runnable) {
        // 开启多线程
        new Thread(runnable).start();
    }

    public static void main(String[] args) {
        // 调用 startThread() 方法,方法的参数是一个接口,那么可以传递这个接口的匿名内部类
        startThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " --> " + "线程已启动");  // Thread-0 --> 线程已启动
            }
        });

        // 调用 startThread() 方法,方法的参数是一个函数式接口,所以可以传递Lambda表达式
        startThread( () -> {
            System.out.println(Thread.currentThread().getName() + " --> " + "线程已启动");  // Thread-1 --> 线程已启动
        });
    }

}

使用Lambda作为返回值

如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个 Lambda 表达式。当需要通过一个方法来获取一个 java.util.Comparator 接口类型的对象作为排序器时,就可以调该方法获取

public class RunnableDemo {

    // 定义方法的返回值类型使用函数式接口 Comparator
    public static Comparator<String> getComparator() {
        // 1. 方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
        return new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 字符串降序
                return o2.length() - o1.length();
            }
        };

        // 2. 方法的返回值类型是一个函数式接口,那么我们可以返回这个接口的Lambda表达式
        return (String o1, String o2) -> {
            // 字符串降序
            return o2.length() - o1.length();
        };

        // 3. 简化 Lambda
        return (o1, o2) -> o2.length() - o1.length();
    }

    public static void main(String[] args) {
        String[] array = {"aaa", "bbb", "cccc", "DDDDD"};
        // 未排序
        Arrays.stream(array).forEach(System.out::println);
        System.out.println("===========================");
        // 排序
        Arrays.sort(array, getComparator());
        Arrays.stream(array).forEach(System.out::println);
    }

}

Stream

Stream简介

Stream:流,是一个来自数据源的元素队列并支持聚合操作

相关概念:

  • 元素:特定类型的对象,形成一个队列 Java 中的 Stream 并不会存储元素,而是按需计算
  • 数据源:流的来源。 可以是集合,数组,I/O channel, 构造器 generator 等
  • 聚合操作:类似SQL语句一样的操作, 比如 filter, map, reduce, find, match, sorted 等

组成:数据源 --> 中间操作(filter、sorted、map)--> 终端操作(collect)

作用:

  • 极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码
  • 将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等

特点:

Stream应用

Stream创建

  • 值创建流
  • 数组创建流
  • 文件生成流
  • 函数生成流(无限流)
  • stream():为集合创建串行流
  • parallelStream():为集合创建并行流

所有的 Collection 集合都可以通过 stream 默认方法获取流
Stream 接口的静态方法 of 可以获取数组对应的流

public class StreamDemo {

    public static void main(String[] args) {
        // 集合转换为Stream
        ArrayList<String> list = new ArrayList<>();
        Stream<String> listStream = list.stream();

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

        HashMap<String, String> map = new HashMap<>();
        // key -> value
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> entryStream = entries.stream();
        // key存储在Map
        Set<String> keySet = map.keySet();
        Stream<String> mapStream = keySet.stream();
        // value存储在Collection
        Collection<String> valueCollection = map.values();
        Stream<String> collectionStream = valueCollection.stream();

        // 数组转换为Stream
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        String[] array = {"hefery", "lalala", "hahaha"};
        Stream<String> integerListStream = Stream.of(array);
    }

}

Stream操作

  • 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用
  • 终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样的链式调用。终结方法包括 count 和 forEach 方法
public class StreamDemo {

    public static void main(String[] args) {
	// POJO
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 23, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 24, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 55, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 67, "female", "New York"));

        // String数组
        List<String> stringList = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");

	// Integer数组
        List<Integer> integerList = Arrays.asList(7, 6, 9, 4, 11, 6);
    }
}
遍历
  • foreach:forEach(System.out::println)
  • peek
过滤
  • filter:通过设置的条件过滤出元素
匹配
  • findFirst:匹配第一个
  • findAny:匹配任意
  • anyMatch:filter + findAny,是否存在
  • allMatch:全部匹配
  • noneMatch:不匹配
public class StreamDemo {
    public static void main(String[] args) {
        // 筛选 age>24 的 Person,并取第一个
        Optional<Person> first = personList.stream().filter(person -> person.getAge() > 24).findFirst();
        Optional<Person> any = personList.stream().filter(person -> person.getAge() > 24).findAny();
        boolean anyMatch = personList.stream().anyMatch(person -> person.getAge() > 24);
        System.out.println("age 大于 24 的第一人:" + first);  // age 大于 24 的第一人:Optional[Person(name=Owen, salary=9500, age=55, sex=male, area=New York)]
        System.out.println("age 大于 24 的任一人:" + any);    // age 大于 24 的任一人:Optional[Person(name=Owen, salary=9500, age=55, sex=male, area=New York)]
        System.out.println("是否存在 age 大于 24 的人:" + anyMatch);  // 是否存在 age 大于 24 的人:true
    }
}
聚合
  • distinct:去重
  • limit:限制
  • skip:跳过
public class StreamDemo {
    public static void main(String[] args) {
        // 获取String集合中最长的元素
        Optional<String> maxString = stringList.stream().max(Comparator.comparing(String::length));
        System.out.println("最长的 String:"+ maxString);  // 最长的 String:Optional[weoujgsd]
        // 自然排序
        Optional<Integer> maxInteger1 = integerList.stream().max(Integer::compareTo);
        // 自定义排序
        Optional<Integer> maxInteger2 = integerList.stream().max(
            (o1, o2) -> o1.compareTo(o2)
        );
        /*Optional<Integer> maxInteger2 = list2.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });*/
        System.out.println("自然排序的最大值:" + maxInteger1.get());    // 自然排序的最大值:11
        System.out.println("自定义排序的最大值:" + maxInteger2.get());  // 自定义排序的最大值:11

        // 获取员工工资最高的人
        Optional<Person> maxSalaryPerson = personList.stream().max(Comparator.comparingInt(Person::getSalary));
        System.out.println("员工工资最大值:" + maxSalaryPerson.get().getSalary());  // 员工工资最大值:9500

        // 计算Integer集合中大于6的元素的个数
        long count = integerList.stream().filter(x -> x>6).count();
        System.out.println("integerList中大于6的元素个数:" + count);  // integerList中大于6的元素个数:3

        // concat:合并两个流 distinct:去重
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };
        List<String> newConcat = Stream.concat(Stream.of(arr1), Stream.of(arr2)).distinct().collect(Collectors.toList());
        // limit:限制从流中获得前n个数据
        List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
        // skip:跳过前n个数据
        List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
        System.out.println("流合并:" + newConcat);  // 流合并:[a, b, c, d, e, f, g]
        System.out.println("limit:" + collect);    // limit:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
        System.out.println("skip:" + collect2);    // skip:[3, 5, 7, 9, 11]
    }
}
映射
  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
public class StreamDemo {
    public static void main(String[] args) {
        // 字符串数组的元素全部改为大写。整数数组每个元素+3
        stringList.stream().map(String::toUpperCase).collect(Collectors.toList()).forEach(System.out::println);  // ADNM ADMMT POT XBANGD WEOUJGSD
        integerList.stream().map(x -> x+3).collect(Collectors.toList()).forEach(System.out::println);  // 10 9 12 7 14 9

        // 将员工的薪资全部增加1000
        //personList.stream().map(person -> person.getSalary()+1000).collect(Collectors.toList()).forEach(System.out::println);
        // 不改变原来员工集合的方式
        List<Person> personListNew = personList.stream().map(person -> {
            Person personNew = new Person(person.getName(), 0, 0, null, null);
            personNew.setSalary(person.getSalary() + 1000);
            return personNew;
        }).collect(Collectors.toList());
        System.out.println("一次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());        // 一次改动前:Tom-->8900
        System.out.println("一次改动后:" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());  // 一次改动后:Tom-->9900
        // 改变原来员工集合的方式
        List<Person> personListNew2 = personList.stream().map(person -> {
            person.setSalary(person.getSalary() + 1000);
            return person;
        }).collect(Collectors.toList());
        System.out.println("二次改动前:" + personList.get(0).getName() + "-->" + personListNew.get(0).getSalary());     // 二次改动前:Tom-->9900
        System.out.println("二次改动后:" + personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary()); // 二次改动后:Tom-->9900
  
        // 将两个字符数组合并成一个新的字符数组
        List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
        List<String> listNew = list.stream().flatMap(s -> {
            // 将每个元素转换成一个stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        }).collect(Collectors.toList());
        System.out.println("处理前的集合:" + list);     // 处理前的集合:[m,k,l,a, 1,3,5,7]
        System.out.println("处理后的集合:" + listNew);  // 处理后的集合:[m, k, l, a, 1, 3, 5, 7]

        // Integer集合的元素之和、乘积和最大值
        // 求和
        Optional<Integer> sum1 = integerList.stream().reduce((x, y) -> x + y);
        Optional<Integer> sum2 = integerList.stream().reduce(Integer::sum);
        Integer sum3 = integerList.stream().reduce(0, Integer::sum);
        // 乘积
        Optional<Integer> product = integerList.stream().reduce((x, y) -> x * y);
        // 最大值
        Optional<Integer> max1 = integerList.stream().reduce((x, y) -> x > y ? x : y);
        Integer max2 = integerList.stream().reduce(1, Integer::max);
        System.out.println("integerList求和:" + sum1.get() + "," + sum2.get() + "," + sum3);  // integerList求和:43,43,43
        System.out.println("integerList求积:" + product.get());              // integerList求积:99792
        System.out.println("integerList求最值:" + max1.get() + "," + max2);  // integerList求最值:11,11

        // 所有员工的工资之和和最高工资
        // 工资之和
        Optional<Integer> sumSalary1 = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        Integer sumSalary2 = personList.stream().reduce(
                0,
                (sum, p) -> sum += p.getSalary(),
                (sumSalaryTemp1, sumSalaryTemp2) -> sumSalaryTemp1 + sumSalaryTemp2
        );
        Integer sumSalary3 = personList.stream().reduce(
                0,
                (sum, p) -> sum += p.getSalary(),
                Integer::sum
        );
        // 最高工资
        Integer maxSalary1 = personList.stream().reduce(
                0,
                (max, p) -> max > p.getSalary() ? max : p.getSalary(),
                Integer::max
        );
        Integer maxSalary2 = personList.stream().reduce(
                0,
                (max, p) -> max > p.getSalary() ? max : p.getSalary(),
                (maxSalaryTemp1,maxSalaryTemp2) -> maxSalaryTemp1 > maxSalaryTemp2 ? maxSalaryTemp1 : maxSalaryTemp2
        );
        System.out.println("工资之和:" + sumSalary1.get() + "," + sumSalary2 + "," + sumSalary3);  // 工资之和:55300,55300,55300
        System.out.println("最高工资:" + maxSalary1 + "," + maxSalary2);  // 最高工资:10500,10500
    }
}
归约
  • reduce:把 Stream 流缩减成一个值,能实现对集合求和、求乘积和求最值操作
  • max:最大
  • min:最小
  • count:计数
收集
  • concat:合并两个流

  • collect:将处理完的流存入新集合,依赖 Collectors 类内置的静态方法

    • 计数:count
    • 平均值:averagingInt、averagingLong、averagingDouble
    • 最值:maxBy、minBy
    • 求和:summingInt、summingLong、summingDouble
    • 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
    • 接合:joining,将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串

收集器接口 Collectors

  • toList:
  • toSet:
  • toMap:
  • toCollection:
  • toConcurrentMap:

Collectors.partitioningBy(item -> item%2==0) // 按奇偶分区
Collectors.groupingBy(item -> item) // 按元素分区

public class StreamDemo {
    public static void main(String[] args) {
        // 筛选员工中工资高于8000的人,并形成新的集合
        List<Person> fiterList = personList.stream().filter(x -> x.getSalary()>8000).collect(Collectors.toList());
        System.out.println("高于8000的员工姓名:" + fiterList);  // 高于8000的员工姓名:[Person(name=Tom, salary=8900, age=23, sex=male, area=New York), Person(name=Anni, salary=8200, age=24, sex=female, area=New York), Person(name=Owen, salary=9500, age=55, sex=male, area=New York)]
        // toList、toSet、toMap
        List<Integer> arrayList = integerList.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        Set<Integer> set = integerList.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
        Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println("toList:" + arrayList);  // toList:[6, 4, 6]
        System.out.println("toSet:" + set);         // toSet:[4, 6]
        System.out.println("toMap:" + map);         // toMap:{Tom=Person(name=Tom, salary=9900, age=23, sex=male, area=New York), Owen=Person(name=Owen, salary=10500, age=55, sex=male, area=New York), Anni=Person(name=Anni, salary=9200, age=24, sex=female, area=New York), Alisa=Person(name=Alisa, salary=8900, age=67, sex=female, area=New York), Lily=Person(name=Lily, salary=8800, age=24, sex=female, area=Washington)}

        // 求总数
        Long countPerson = personList.stream().collect(Collectors.counting());
        // 求平均工资
        Double averagePersonSalary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
        // 求最高工资
        Optional<Integer> maxPersonSalary = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
        // 求工资之和
        Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
        // 一次性统计所有信息
        DoubleSummaryStatistics collectaveragePersonSalary = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
        System.out.println("员工总数:" + countPerson);  // 员工总数:6
        System.out.println("员工平均工资:" + averagePersonSalary);  // 员工平均工资:9216.666666666666
        System.out.println("员工工资总和:" + maxPersonSalary);  // 员工工资总和:Optional[10500]
        System.out.println("员工工资所有统计:" + collectaveragePersonSalary);  // 员工工资所有统计:DoubleSummaryStatistics{count=6, sum=55300.000000, min=8000.000000, average=9216.666667, max=10500.000000}
  
        // 接合(joining)
        String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println("所有员工的姓名:" + names);   // 所有员工的姓名:Tom,Jack,Lily,Anni,Owen,Alisa
        String string = stringList.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串:" + string);  // 拼接后的字符串:adnm-admmt-pot-xbangd-weoujgsd

        // concat:合并两个流 distinct:去重
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };
        List<String> newConcat = Stream.concat(Stream.of(arr1), Stream.of(arr2)).distinct().collect(Collectors.toList());
        System.out.println("流合并:" + newConcat);  // 流合并:[a, b, c, d, e, f, g]
    }
}
分组
  • partitioningBy:分区:将stream按条件分为两个Map
  • groupingBy:分组:将集合分为多个Map
public class StreamDemo {
    public static void main(String[] args) {
        // 将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组
        // 将员工按薪资是否高于8000分组
        Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
        // 将员工按性别分组
        Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        // 将员工先按性别分组,再按地区分组
        Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
        System.out.println("员工按薪资是否大于8000分组情况:" + part);  // 员工按薪资是否大于8000分组情况:{false=[Person(name=Jack, salary=8000, age=23, sex=male, area=Washington)], true=[Person(name=Tom, salary=9900, age=23, sex=male, area=New York), Person(name=Lily, salary=8800, age=24, sex=female, area=Washington), Person(name=Anni, salary=9200, age=24, sex=female, area=New York), Person(name=Owen, salary=10500, age=55, sex=male, area=New York), Person(name=Alisa, salary=8900, age=67, sex=female, area=New York)]}
        System.out.println("员工按性别分组情况:" + group);  // 员工按性别分组情况:{female=[Person(name=Lily, salary=8800, age=24, sex=female, area=Washington), Person(name=Anni, salary=9200, age=24, sex=female, area=New York), Person(name=Alisa, salary=8900, age=67, sex=female, area=New York)], male=[Person(name=Tom, salary=9900, age=23, sex=male, area=New York), Person(name=Jack, salary=8000, age=23, sex=male, area=Washington), Person(name=Owen, salary=10500, age=55, sex=male, area=New York)]}
        System.out.println("员工按性别、地区:" + group2);  // 员工按性别、地区:{female={New York=[Person(name=Anni, salary=9200, age=24, sex=female, area=New York), Person(name=Alisa, salary=8900, age=67, sex=female, area=New York)], Washington=[Person(name=Lily, salary=8800, age=24, sex=female, area=Washington)]}, male={New York=[Person(name=Tom, salary=9900, age=23, sex=male, area=New York), Person(name=Owen, salary=10500, age=55, sex=male, area=New York)], Washington=[Person(name=Jack, salary=8000, age=23, sex=male, area=Washington)]}}
    }
}
排序
  • sorted():自然排序,流中元素需实现Comparable接口
  • sorted(Comparator com):Comparator排序器自定义排序
public class StreamDemo {
    public static void main(String[] args) {
        // 将员工按工资由高到低(工资一样则按年龄由大到小)排序
        // 按工资升序排序(自然排序)
        List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName).collect(Collectors.toList());
        // 按工资倒序排序
        List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).map(Person::getName).collect(Collectors.toList());
        // 先按工资再按年龄升序排序
        List<String> newList3 = personList.stream()
                .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
                .collect(Collectors.toList());
        // 先按工资再按年龄自定义排序(降序)
        List<String> newList4 = personList.stream().sorted((p1, p2) -> {
            if (p1.getSalary() == p2.getSalary()) {
                return p2.getAge() - p1.getAge();
            } else {
                return p2.getSalary() - p1.getSalary();
            }
        }).map(Person::getName).collect(Collectors.toList());
        System.out.println("按工资升序排序:" + newList);   // 按工资升序排序:[Jack, Lily, Alisa, Anni, Tom, Owen]
        System.out.println("按工资降序排序:" + newList2);  // 按工资降序排序:[Owen, Tom, Anni, Alisa, Lily, Jack]
        System.out.println("先按工资再按年龄升序排序:" + newList3);       // 先按工资再按年龄升序排序:[Jack, Lily, Alisa, Anni, Tom, Owen]
        System.out.println("先按工资再按年龄自定义降序排序:" + newList4);  // 先按工资再按年龄自定义降序排序:[Owen, Tom, Anni, Alisa, Lily, Jack]
    }
}

标题:Java基础—Lambda+Stream
作者:Hefery
地址:http://hefery.icu/articles/2022/03/16/1647363164528.html