一文掌握Java8Stream流的常见用法

前言

在jdk8的时候推出了Stream流,它配合上lambda表达式,可以大大简化功能的实现。如果不懂或者是没了解过Stream流的话,那么看Stream流相关的代码会很难受。但是如果真的掌握了他的用法的话,那么就只能用两个来形容,那就是:真香。
为了避免一些生硬的概念的出现,我就在下文中直接举例子,通过例子来掌握Stream流的用法。

在整个Stream流中,其实可以分为两个部分:中间操作、终端操作。下面就对这两部分相关的API来直接举例演示。

中间操作

创建一些需要举例的数据:

public class Animal {
    private String name;
    private int foot,age;
    private BigDecimal money;

    public Animal(String name, int foot, int age, BigDecimal money) {
        this.name = name;
        this.foot = foot;
        this.age = age;
        this.money = money;
    }

    public BigDecimal getMoney() {
        return money;
    }

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

    public int getAge() {
        return age;
    }

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

    public int getFoot() {
        return foot;
    }

    public void setFoot(int foot) {
        this.foot = foot;
    }

    public String getName() {
        return name;
    }

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

然后定义一个list集合填充对象的数值:

List<Animal> animalList = new ArrayList<Animal>() {
            {
                add(new Animal("dog", 4, 4, BigDecimal.valueOf(10)));
                add(new Animal("cat", 4, 6,BigDecimal.valueOf(11)));
                add(new Animal("duck", 2, 3,BigDecimal.valueOf(12)));
                add(new Animal("chick", 2, 1,BigDecimal.valueOf(13)));
                add(new Animal("pig", 4, 3,BigDecimal.valueOf(12)));
                add(new Animal("horse", 4, 3,BigDecimal.valueOf(14)));
            }
        };
filter:过滤

他会以filter中的内容作为条件,将符合filter括号内的内容筛选过滤出来。比如我们想要得到年龄大于3的动物;

List<Animal> collect = animalList.stream()
                .filter(p -> p.getAge() > 3)
                .collect(Collectors.toList());

我们看下他的格式,起始是一个list集合,可以理解为数据源,然后跟了一个stream,也就是将集合转换为了流,这样的话就方便我们在后面对他进行流式处理。

filter:过滤,里面就是我们的条件,至于最后的collect,也就是收集,将前面一步得到的符合年龄大于3岁的数据收集起来作为一个list返回。

对于大部分的stream流来说,他的结构都是如此,所以在这里记得格式是这么个格式就OK。

除此之外,Stream还支持自定义过滤器、多个过滤条件。

 /*找出年龄大于2,并且脚数也大于2的动物*/
        Predicate<Animal> ageFilter=(p)->(p.getAge()>2);
        Predicate<Animal> footFilter=(p)->(p.getFoot()>2);
        List<Animal> collect = animalList.stream()
                .filter(ageFilter)
                .filter(footFilter)
                .collect(Collectors.toList());
sort:排序

比如我想要按照年龄从小到大来进行排序,这个用stream来实现也是极为简单的:

List<Animal> collect = animalList.stream().sorted((p, p1) -> (p1.getAge() - p.getAge())).collect(Collectors.toList());

那如果从大到小呢?p和p1调个位置嘛。

ok,这是数值,可以进行减法运算,那我名字是字符,这个该怎么进行排序呢?Stream的sort也是可以对这种类型排序的:

List<Animal> collect = animalList.stream().sorted(Comparator.comparing(Animal::getName)).collect(Collectors.toList());

这个就是按照26个英文字母的顺序来进行正序排序的。如果你想按照英文字母从后向前排序,那么在comparing()后面加个reversed即可。

max、min(最大、最小值)

Stream流提供了max、min可以让我们更加方便的找出集合中的最大最小值。

集合中age最大的动物:

Animal animal = animalList
                .stream()
                .max((p, p1) -> p.getAge() - p1.getAge())
                .get();
System.out.println(animal.getName());

因为结果是个确定的值嘛,所以使用.get()获取结果即可。.get()也是流结束的一个标志。

最小值:

Animal animal = animalList
                .stream()
                .min((p, p1) -> p.getAge() - p1.getAge())
                .get();
System.out.println(animal.getName());

#### limit:个数限制
 找到集合中前三个元素:
 

```java
List<Animal> collect = animalList
                .stream()
                .limit(3)
                .collect(Collectors.toList());
collect.forEach((p)-> System.out.println(p.getName()));
map:元素映射

假如你想将集合中所有元素的某个属性放在一起,那么map将会是非常方便的方法。
获取集合中所有动物的名称:

List<String> collect = animalList.stream()
                .map(Animal::getName)
                .collect(Collectors.toList());

这种对象是可以以这样的形式来写的,但是对于Map来说,却无法这样实现。因为map有别的方式:

List<Map<String,Integer>> testMapList = new ArrayList<>();
        testMapList.add(new HashMap(){{
            put("key",1);
        }});

        testMapList.add(new HashMap(){{
            put("key",2);
        }});
        List<Integer> key = testMapList.stream()
                .map(p -> p.get("key"))
                .collect(Collectors.toList());
distinct:去重

这个去重就很好理解了嘛,但是为了加深上面的map的印象,我们就将它们放在一起来看。
比如想找出这个集合中,共有多少个不同的年龄。
那就需要执行两步,第一步是通过map获取到集合中的所有的年龄,第二步就是执行去重。

List<Integer> collect = animalList.stream().map(Animal::getAge).distinct().collect(Collectors.toList());

limit:限制 skip:跳过

这两个放在一块展示了,因为性质其实差不多。
limit:限制取出前面n个。
skip:跳过前面n个,获取第n个后面的值,

List<Animal> collect = animalList.stream().limit(3).collect(Collectors.toList());
List<Animal> collect = animalList.stream().skip(3).collect(Collectors.toList());
summaryStatistics

如果你需要获取集合中某个属性的值的和、获取平均数之类的,那么使用summaryStatistics将会很方便:

IntSummaryStatistics intSummaryStatistics = animalList
                .stream()
                .mapToInt(p -> p.getAge())
                .summaryStatistics();
 System.out.println(intSummaryStatistics.getMax());
 System.out.println(intSummaryStatistics.getMin());
 System.out.println(intSummaryStatistics.getAverage());

终端操作

collect

前面我们的例子中一直以这个collect结尾,在这里我们终于要知道这个collect的用法了。前面例子中collect里面是Collectors.toList(),也就是返回值类型是一个list,除了这个Collectors.toList(),还有Collectors.toSet(),想必聪明的各位也能够猜的出来。没错,他的返回值类型就是Set。
不过除了这两个,我想介绍下Collectors.joining()。他可以将前面的流中的数据并起来。如果想把集合中的所有name并起来,并且以","作为分割,那么这个方法就派上用场了:

String collect = animalList.stream().map(Animal::getName).collect(Collectors.joining("-"));
grouping by:分组

在不用Stream流之前,感觉要对数据进行分组的话,那可老麻烦了。但是用了这个grouping by,那么就不一样了。
以年龄进行分组:

Map<Integer, List<Animal>> collect = animalList.stream().collect(Collectors.groupingBy(Animal::getAge));

而且还支持再一次分组:

Map<Integer, Map<Integer, List<Animal>>> collect = animalList.stream().collect(Collectors.groupingBy(Animal::getFoot, Collectors.groupingBy(Animal::getAge)));

看着都神清气爽,比循环分组实在是方便多了。

reduce归约

因为在开发中会对金额做处理,而金额又是BigDecimal类型的。如果要是求得集合中金额的总和,那么使用这个reduce就很方便了:

  BigDecimal reduce = animalList.stream().map(p -> {
      if (p.getMoney() == null) {
          return BigDecimal.ZERO;
      } else {
          return p.getMoney();
      }
  }).reduce(BigDecimal.ZERO, BigDecimal::add);

它不仅支持金额相加操作,还支持相减、相乘、相除等操作。

而且,除了BigDecimal类型,对于Integer类型也是同样支持的:

Integer reduce = animalList.stream().map(Animal::getAge).reduce(0, Integer::sum);

匹配anyMatch、allMatch、nonMatch

他们三个分别为:
任意一个匹配:只要有一个符合条件,就返回true。
全部匹配:只有所有数据都符合条件时,才返回true。
没有一个匹配:只有所有数据都不符合条件时,才返回true。
用法如下:

boolean b = animalList.stream().anyMatch(p ->p.getAge()==10);

boolean b1 = animalList.stream().noneMatch(p -> p.getAge() == 10);

boolean b2 = animalList.stream().allMatch(p -> p.getAge() == 4);

总结

以上就是关于Stream流的常见用法了,我觉得可以涵盖大部分的使用场景,毕竟是一个工具类,只要多多练习,掌握它还是不难的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值