jkd1.8 stream

Stream

创建流

通过集合创建,例如Map (常用)

Stream<Map.Entry<Object, Object>> stream = new HashMap<>().entrySet().stream();

通过数组方式创建

Stream stream = Arrays.asList(new String[]{"1", "2", "3"}).stream();

通过Stream静态方法创建

1、 使用静态方法创建流
Stream stringStream = Stream.of("1", "2", "3");
2、 通过Java 8 函数式接口Supplier创建无限流(无限流将在下一篇为大家介绍)
Stream generateStream = Stream.generate(UUID::randomUUID);
3、 通过Java 8 函数式接口UnaryOperator创建无限流
Stream iterateStream = Stream.iterate(1, x -> x + 1);
一般无限流和limit一起使用

    public static Integer x = 0;

    public static void main(String[] args) {
        Stream<Integer> limit = Stream.iterate(x, x -> x + 1).limit(10L);//0-9
    }

中间操作

筛选和切片

filter

从流中过滤掉一些元素

limit

截断流,使得元素不超过给定数量

skip

跳过元素,返回一个扔掉了前n个元素的流,如果元素个数不足n,则返回一个空流

distinct

去重,通过流所生成元素的hashcode和equal方法去除重复的元素

映射

map

接受一个Lambda表达式,将流里面的元素转化为其他的元素,该函数会应用于每一个函数上,并映射成为一个新的元素。

flatmap

接受一个函数作为接受,一般是将流里面的元素转为另外一个流,再将这个流连接起来。

map和flatmap的区别

map的作用是对list中每个元素进行重新定义和包装。
flatmap的作用是把几个小的list转换到一个大的list

案例

将{"hello","world"}转化为{'h','e','l','l','o','w','o','r','l','d'}


/**
 * 将{"hello","world"}转化为{'h','e','l','l','o','w','o','r','l','d'}
 */
public class MapTest {
    @Test
    public void test() {

        List<String> list = new ArrayList<>(Arrays.asList("hello", "world"));

        //i.chars().mapToObj(c -> (char) c)是将字符串转为Character流
        //map 无法实现此功能
        Stream<Stream<Character>> stream = list.stream().map(i -> i.chars().mapToObj(c -> (char) c));

        Stream<Character> characterStream = list.stream().flatMap(i -> i.chars().mapToObj(c -> (char) c));

        List<Character> collect = characterStream.collect(Collectors.toList());

        collect.forEach(System.out::println);

    }
}

排序

sorted()

自然排序按照comparable排序

sorted(Comparator c)

自定排序规则

终止操作

forEach

对于每个元素消费

查找和匹配

allMatch

是否匹配所有元素

anyMatch

是否匹配至少一个元素

noneMatch

是否没有匹配所有元素

findFirst

查找第一个元素

findAny

查找任意一个元素

count

计算元素个数

max

查找最大值

min

查找最小值

规约和收集

reduce

Optional reduce(BinaryOperator accumulator);
T reduce(T identity, BinaryOperator accumulator);
将流中的元素反复结合起来,形成一个值


    /*
    通过reduce求和
     */
    @Test
    public void test1() {
        Optional<Double> reduce = list.stream().map(Employee::getSalary).reduce((x, y) -> x + y);
    }

    /*
    reduce在100的基础上求和
     */
    @Test
    public void test2() {
        Double reduce = list.stream().map(Employee::getSalary).reduce(100D, (x, y) -> x + y);
    }

toArray

    /**
     * 将名字收集为字符串数组
     */
    @Test
    public void test3(){
        String[] names = list.stream().map(Employee::getName).toArray(String[]::new);
    }

collect

    /**
     * 将名字收集为字符串数组
     */
    @Test
    public void test3() {
        String[] names = list.stream().map(Employee::getName).toArray(String[]::new);
    }

    /**
     * 将名字收集为集合
     */
    @Test
    public void test4() {
        List<String> collect1 = list.stream().map(Employee::getName).collect(Collectors.toList());
        ArrayList<String> collect = list.stream().map(Employee::getName).collect(Collectors.toCollection(ArrayList::new));
    }

    /**
     * 计数
     */
    @Test
    public void test5() {
        long count = list.stream().map(Employee::getName).collect(Collectors.counting());
        long count1 = list.stream().map(Employee::getName).count();
    }

    /**
     * 求平均值
     */
    @Test
    public void test6() {
        Double collect = list.stream().collect(Collectors.averagingDouble(Employee::getSalary));
    }

    /**
     * 求和
     */
    @Test
    public void test7() {
        Double collect = list.stream().collect(Collectors.summingDouble(Employee::getSalary));
        Double collect1 = list.stream().mapToDouble(Employee::getSalary).sum();
    }

    /**
     * 分组
     */
    @Test
    public void test8() {
        Map<State, List<Employee>> collect = list.stream().collect(Collectors.groupingBy(i -> i.getState()));
    }

    /**
     * 分片
     */
    @Test
    public void test9() {
        Map<Boolean, List<Employee>> collect = list.stream().collect(Collectors.partitioningBy(i -> i.getSalary() > 10));
    }

    /**
     * 连接字符串
     */
    public void test10() {
        String collect = list.stream().map(Employee::getName).collect(Collectors.joining(",", "(", ")"));
    }

collect经典应用

1、将一下Person的List通过名字筛选出每个人的money总数

        ArrayList<Person> list = new ArrayList<>(Arrays.asList(
                new Person("tom", 1, 100),
                new Person("jack", 2, 100),
                new Person("tom", 1, 100),
                new Person("jack", 2, 100),
                new Person("jack", 2, 100),
                new Person("marry", 3, 100)
        ));


class Person {
    private String name;
    private Integer age;
    private Integer money;


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return name.equals(person.name) &&
                age.equals(person.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    public Person(String name, Integer money) {
        this.name = name;
        this.money = money;
    }

    public Person(String name, Integer age, Integer money) {
        this.name = name;
        this.age = age;
        this.money = money;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getMoney() {
        return money;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }
}

答案

        List<Person> ans = list.stream()
                .collect(Collectors.groupingBy(Person::getName, Collectors.summingInt(Person::getMoney)))
                .entrySet()
                .stream()
                .map(i -> new Person(i.getKey(), i.getValue()))
                .collect(Collectors.toList());

2、通过以上方法获取的person会把age字段丢失,因为groupingBy是通过hashcode来做分组,要保留name和age两个字段的方法有两个。

  • 将name和age单独封装为一个类,这样的做法和第一题差不多
  • 如果name和age是一一对应的,比如tom就是1岁,是确定的,那么可以重写hashcode函数,这样name和age相同的对象就会被分到一个组。
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return name.equals(person.name) &&
                age.equals(person.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

code

        List<Person> collect1 = list.stream()
                .collect(Collectors
                        //关键这里的i->i,会将name和age相同的分为一组
                        .groupingBy(i -> i, Collectors.summingInt(Person::getMoney)))
                .entrySet()
                .stream()
                .map(i -> new Person(i.getKey().getName(), i.getKey().getAge(), i.getValue()))
                .sorted(Comparator.comparingInt(Person::getAge))
                .collect(Collectors.toList());

posted @ 2020-08-28 10:42  刃牙  阅读(161)  评论(0编辑  收藏  举报