关于java8Stream的简单理解

本文详细介绍了Java 8中Stream的四大核心接口(Consumer, Supplier, Function, Predicate),以及如何通过各种方式构建Stream,进行中间操作如过滤、映射、扁平化等,并演示了终端操作如forEach、collect等在实际场景中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 四大内置核心函数式接口

1. Consumer:消费型接口 void accept(T t);
消费型接口就是传进去参数经过表达式处理,没有返回值。 

public void test(){
    shopping(1000,(x)-> System.out.println("今天购物发了"+x+"元"));
}
public  void shopping(double money, Consumer<Double> con){
	con.accept(money);
}

2. Supplier :供给型接口 T get();
供给型接口就是无中生有,不传参经过表达式处理返回值,比如生成随机数

public void test2(){
	List<Integer> numList=getNumList(3,()->(int)(Math.random()*10));
}
   
public List<Integer> getNumList(int num, Supplier<Integer> sup){
    List<Integer> list=new ArrayList<>();
    for (int i=0;i<num;i++){
        Integer n=sup.get();
        list.add(n);
    }
    return list;
}

3. Function<T,R>: 函数型接口 R apply(T t);
函数型接口有传参有返回值。

public void test3(){
   String newStr= handlerStr("helloworld",(str)->str.substring(3,6));
   System.out.println(newStr);
}

public String handlerStr(String str, Function<String,String> fun){
    return fun.apply(str);
}

 4. Predicate: 断言型接口 boolean test(T t)
返回true或者false

	public void test4(){
        List<String> list= Arrays.asList("idea","eclipse","predicate","function");
        List<String> returnList= filterStr(list,(str)->str.length()>4);  
    }
    public List<String> filterStr(List<String> list, Predicate<String> pre){
        List<String> newList=new ArrayList<>();
        for (String str:list) {
            if(pre.test(str)){
               newList.add(str);
            }
        }
        return newList;
    }

下面直观点了解Stream:

  • Stream是Java8 新增的流特性,目的是让程序员写出高效率、干净、简洁的代码
  • Stream类似于SQL语句,可以对代码进行集合运算和表达
  • Stream就是把元素看成一种流,流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
     

Stream使用格式成如下图 :

构建Stream  ------------中间操作----------------------终端操作 

注意:在没有终端操作 的前提下,中间操作即生成流不会执行 

数据源:分为串行流Stream和并行流parallelStream()

        列举一下构建串行流的方式,与并行流类似 

  •         构建Stream流的4中途径

  1.         通过数组 Arrays.stream
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: DIXian
 * @Date: 2021/07/04/19:31
 */
public class Test04 {
    public static void main(String[] args) {
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
        Stream<Integer> stream = integers.stream();
        stream.forEach(System.out::println);
    }
}

   2.          通过集合Collection.stream

    @Test
    public void test01(){

        ArrayList<Object> list = new ArrayList<>();
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.stream().forEach(System.out:: println);

    }
}

 3.        通过Stream的静态of()方法Stream.of

    @Test
    public void test02(){
        Stream.of(2, 3, 4, 5).forEach(System.out :: println);
    }
}

4.        通过创建无限流的两种方式

  • Stream.iterate
  • Stream.generate
  @Test
    public void test03(){
        //seed :给定一个初始值 ,后一个参数 T -> t ,此处加个一个截断操作 limit(10)
        Stream.iterate(0, item -> item+2).limit(10).forEach(System.out :: println);
    }

生成流:即对构建好的进行中间操作

  • filter()
  • map()
  • flatMap()
  • distinct()
  • sorted()
  • peek()
  • limit()
  • skip()

1. filter():filter(): 返回结果生成新的流中只包含满足筛选条件的数据。

 public void test04(){
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
        integers.stream().filter(item -> item.equals(1)).forEach(System.out :: println);


    }

2.map():将流中的元素进行再次加工形成一个新流,流中的每一个元素映射为另外的元素。

// 2、map:返回元素的大写类型和哈希值
        List<String> mzc = Arrays.asList("ma", "zhi", "chu");
        List<String> mzcUpperCase = mzc.stream().
                map(n -> n.toUpperCase()).
                collect(Collectors.toList());
        List<Integer> mzcHashCode = mzc.stream().map(n -> n.hashCode()).collect(Collectors.toList());
        System.out.println("mzcUpperCase:"+mzcUpperCase+" ----- mzcHashCode:"+mzcHashCode);

运行结果:

        mzcUpperCase:[MA, ZHI, CHU] ----- mzcHashCode:[3476, 120571, 98480] 

示例场景:取出商品的所有id,就可以这样写(伪代码):

List<Product> productList = productService.selectAll();

List<Integer> pIds = productList.stream().map(p->p.getId).collect(Collectors.toList());

这样就可以拿到所有商品id的集合。

 3.flatMap():扁平化映射,它具体的操作是将多个stream连接成一个stream,这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用,类似list中的addAll()操作

flatMap是将流中的每个元素都放到一个流中,最后将所有的流合并成一个新流,所有流对象中的元素都合并到这个新生成的流中返回。

// flatMap:将多层集合中的元素取出来,放到一个新的集合中去
        List<Integer> num1 = Arrays.asList(1, 2, 3);
        List<Integer> num2 = Arrays.asList(4, 5, 6);
        List<Integer> num3 = Arrays.asList(7, 8, 9);
        List<List<Integer>> lists = Arrays.asList(num1, num2, num3);
        Stream<Integer> outputStream = lists.stream().flatMap(l -> l.stream());
        List<Integer> flatMapResult = outputStream.sorted().collect(Collectors.toList());
        System.out.println(flatMapResult);

运行结果:[1, 2, 3, 4, 5, 6, 7, 8, 9]

示例场景:取出所有部门人员的姓名,就可以这样写(伪代码):

// 1、取出所有部门

List<Department> departments = ...;

// 2、这个时候可以利用flatMap先将所有部门的所有人员汇聚起来

List<Person> persons = departments.stream.flatMap(d->d.getPersonList()).collect(Collectors.toList());

// 3、再利用map()方法取出

4.distinct():顾名思义,将流中的元素去重之后输出。

List<String> mzc = Stream.of("ma","zhi","chu","zhi","shuo","ma")
        .distinct()
        .collect(Collectors.toList());
System.out.println(mzc);

 运行结果:

[ma, zhi, chu, shuo]

5.sorted():这个很简单了,顾名思义,将流中的元素按照自然排序方式进行排序。

// sorted:自然顺序排序
        List<Integer> nums = Arrays.asList(1, 3, 5, 6, 8, 2);
        List<Integer> sortedNum = nums.stream().sorted().collect(Collectors.toList());
        System.out.println(sortedNum);
 
        // sorted:降序排序
        List<Integer> sortedNum2 = nums.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        System.out.println(sortedNum2);
 
        // sorted:使用Comparator
        List<Integer> sortedNums3 = nums.stream().sorted(Comparator.comparing(n -> n)).collect(Collectors.toList());
        System.out.println(sortedNums3);
 
        // 不用stream直接顺序排序
        nums.sort(Comparator.comparing(Integer::intValue));
        System.out.println(nums);
 
        //不用stream直接降序排序
        nums.sort(Comparator.comparing(Integer::intValue).reversed());
        System.out.println(nums);

运行结果:

[1, 2, 3, 5, 6, 8]

[8, 6, 5, 3, 2, 1]

[1, 2, 3, 5, 6, 8]

[1, 2, 3, 5, 6, 8]

[8, 6, 5, 3, 2, 1]

6.peek():对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。

// peek():
        String[] arr = new String[]{"a","b","c","d"};
        Arrays.stream(arr)
                .peek(System.out::println) //a,b,c,d
                .count();
 
        // peek()+filter()
        Stream.of("ma", "zhi", "chu")
                .filter(e -> e.length() > 2)
                .peek(e -> System.out.println(e))
                .collect(Collectors.toList());

运行结果:

a

b

c

d

zhi

chu

7、limit():顾名思义,返回指定数量的元素的流。返回的是Stream里前面的n个元素。

// limit():取出100中的前十个
        List<Integer> limitNum = IntStream.range(1,100).limit(10)
                .boxed()
                .collect(Collectors.toList());
        System.out.println(limitNum);
 
        // limit():取出前4个单词
        List<String> words = Arrays.asList("ma", "zhi", "chu", "wait", "you", "follow");
        List<String> limitWord = words.stream().limit(4).collect(Collectors.toList());
        System.out.println(limitWord);

运行结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[ma, zhi, chu, wait]

8.skip():和limit()相反,将前几个元素跳过(取出)再返回一个流,如果流中的元素小于或者等于n,就会返回一个空的流。

// skip():跳过前面三个单词再返回
    List<String> words = Arrays.asList("ma", "zhi", "chu", "wait", "you", "follow");
    List<String> skipWord = words.stream().limit(4).collect(Collectors.toList());
    System.out.println(skipWord);
 
    // skip():跳过全部单词再返回
    List<String> emptyWord = words.stream().skip(6).collect(Collectors.toList());
    System.out.println(emptyWord);
 
    // skip():跳过超过单词长度的数目再返回
    List<String> emptyWord2 = words.stream().skip(10).collect(Collectors.toList());
    System.out.println(emptyWord);

运行结果:

[91, 92, 93, 94, 95, 96, 97, 98, 99]

[ma, zhi, chu, wait]

[]

[]

聚合操作:即对流进行终端操作

  • forEach()
  • forEachOrdered()
  • toArray()
  • reduce()
  • collect()
  • min()
  • max()
  • count()
  • anyMatch()
  • allMatch()
  • noneMatch()
  • findFirst()
  • findAny()
  • toMap()

1.forEach():遍历流中的每一个元素,按照指定的方法执行,执行顺序不一定按照流的顺序。

// foreach:遍历流中每一个元素,执行顺序按照流的顺序
Stream.of(1,2,3,4,5,6).forEach(System.out::println);
// foreach:遍历流中每一个元素,执行顺序不一定按照流的顺序,.parallel()表示创建一个并行流
Stream.of(1,2,3,4,5,6).parallel().forEach(System.out::println);

2.forEachOrdered():遍历流中的每一个元素,按照指定的方法执行,执行顺序按照流的顺序。

// forEachOrdered():遍历流中每一个元素,执行顺序按照流的顺序
Stream.of(1,2,3,4,5,6).forEachOrdered(System.out::println);
// forEachOrdered:遍历流中每一个元素,执行顺序按照流的顺序,.parallel()表示创建一个并行流
Stream.of(1,2,3,4,5,6).parallel().forEachOrdered(System.out::println);

运行结果:

1

2

3

4

5

6

1

2

3

4

5

6

3.toArray():将流中的元素放入到一个数组中

// toArray():将流中的元素放入到一个数组中
String[] strings = Stream.of("ma", "zhi", "chu").toArray(String[]::new);
System.out.println(Arrays.toString(strings));

运行结果:[ma, zhi, chu]

4.reduce():这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。

// reduce():字符串拼接
String reduceStr1 = Stream.of("ma", "zhi", "chu").reduce("", String::concat);
String reduceStr2 = Stream.of("ma", "zhi", "chu").reduce("", (x,y)->x+y);
System.out.println(reduceStr1);
System.out.println(reduceStr2);
// reduce():求和,identity(起始值)为0
Integer total1 = Stream.of(1,2,3,4).reduce(0, Integer::sum);
Integer total2 = Stream.of(1,2,3,4).reduce(0, (x, y) -> x +y);
System.out.println(total1);
System.out.println(total2);
// 求和,sumValue = 10, 无起始值
Integer total3 = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println(total3);
// reduce():求最小值
double minValue = Stream.of(-1.1, 8.8, -2.2, -6.6).reduce(Double.MAX_VALUE, Double::min);
System.out.println(minValue);

运行结果:

mazhichu

mazhichu

10

10

10

-6.6

5.collect():是Stream的一个函数,负责收集流。前面我们说中间操作是将一个流转换成另一个流,这些操作是不消耗流的,但是终端操作会消耗流,产生一个最终结果,collect()就是一个规约操作,将流中的结果汇总。结果是由传入collect()中的Collector定义的

// collect():负责收集流,将结果汇总,比如将下面的流中的结果汇总到一个集合中去
List<Integer> skipNum = IntStream.range(1,100).skip(90)
.boxed()
.collect(Collectors.toList());
System.out.println(skipNum);

运行结果:[91, 92, 93, 94, 95, 96, 97, 98, 99]

6.min():返回流中的最小值

// min():返回流中的最小值
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer minNum = nums.stream().min(Integer::compareTo).get();
Integer min = nums.stream().min((x,y) -> x.compareTo(y)).get();
System.out.println(minNum);
System.out.println(min);

运行结果:

1

1

7.max():返回流中的最大值

// max():返回流中的最大值
List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer maxNum = num.stream().max(Integer::compareTo).get();
Integer max = num.stream().max(Comparator.comparing(Function.identity())).get();
System.out.println(maxNum);
System.out.println(max);

运行结果:

6

6

8.count():返回流中元素的数量

// count():返回流中元素的数量
List<Integer> ls = Arrays.asList(1,2,3,4,5);
long count = ls.stream().count();
long count1 = ls.stream().filter(l -> l > 2).count();
System.out.println(count);
System.out.println(count1);

运行结果:

5

3

9.anyMatch():Stream 中只要有一个元素符合传入的断言,就返回 true,否则返回false。

// anyMatch():判断流中数据是否有一个复合断言
List<Integer> ins = Arrays.asList(1,2,3,4,5);
boolean b = ins.stream().anyMatch(l -> l > 2);
boolean b1 = ins.stream().anyMatch(l -> l > 5);
System.out.println(b);
System.out.println(b1);
// anyMatch():判断流中数据是否有一个复合断言,如果流为空,永远返回false
List<Integer> inss = Arrays.asList();
boolean b2 = inss.stream().anyMatch(l -> l > 2);
System.out.println(b2);

运行结果:

true

false

false

10.allMatch():Stream 中所有元素都符合传入的断言时返回 true,否则返回false,流为空时总是返回true。

// allMatch():判断流中元素是否都符合断言条件
List<Integer> ints = Arrays.asList(1,2,3,4,5);
boolean c = ints.stream().allMatch(l -> l > 0);
boolean c1 = ints.stream().allMatch(l -> l > 1);
System.out.println(c);
System.out.println(c1);
// allMatch():判断流中元素是否都符合断言条件,如果流为空,永远返回true
List<Integer> emptyList = new ArrayList<>();
boolean c2 = emptyList.stream().allMatch(e -> e > 1);
System.out.println(c2);

运行结果:

true

false

true

11.noneMatch():Stream 中所有元素都不满足传入的断言时返回 true,否则返回false。

// noneMatch():判断流中元素是否都不符合传入的断言条件
List<Integer> numList = Arrays.asList(1,2,3,4,5);
boolean d = numList.stream().noneMatch(l -> l > 6);
boolean d1 = numList.stream().noneMatch(l -> l > 1);
System.out.println(d);
System.out.println(d1);
// noneMatch():判断流中元素是否都不符合传入的断言条件,流为空时永远返回true
List<Integer> numist = Arrays.asList();
boolean d2 = numist.stream().noneMatch(l -> l > 6);
System.out.println(d2);

运行结果:

true

false

true

12.findFirst():总是返回流中的第一个元素,如果流为空,返回一个空的Optional.

// findFirst():返回流中的第一个元素
List<Integer> integers = Arrays.asList(1, 2, 3);
Optional<Integer> first = integers.stream().findFirst();
System.out.println(first);
System.out.println(first.isPresent()); // 判断是否不等于null,isPresent()相当于!=null的判断
System.out.println(first.get());
//findFirst():返回流中的第一个元素,如果流为空,返回一个空的Optional
List<Integer> lls = Collections.EMPTY_LIST;
Optional<Integer> first1 = lls.stream().findFirst();
System.out.println(first1);
System.out.println(first1.isPresent());

运行结果:

Optional[1]

true

1

Optional.empty

false

13.findAny():返回流中的任意一个元素即可,如果流为空,返回一个空的Optional.

// findAny():返回流中任意一个元素,
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Optional<Integer> any = list.stream().findAny();
// 并行流下每次返回的结果会不同
// Optional<Integer> any = list.stream().parallel().findAny();
System.out.println(any);
System.out.println(any.isPresent());
System.out.println(any.get());
// findAny():返回流中任意一个元素,如果流为空,返回一个空的Optional
List<Integer> list1 = Arrays.asList();
Optional<Integer> any1 = list1.stream().findAny();
System.out.println(any1);
System.out.println(any1.isPresent());

运行结果:

Optional[1]

true

1

Optional.empty

false

以上即为Stram的流程操作理解

14.toMap()

        此为聚合操作中转换为map的操作

使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value。
toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的。
第三个参数用在key值冲突的情况下:如果新元素产生的key在Map中已经出现过了,第三个参数就会定义解决的办法。

在你的例子中
 .collect(Collectors.toMap(UserBo::getUserId, v -> v, (v1, v2) -> v1));
第一个参数UserBo::getUserId 表示选择UserBo的getUserId作为map的key值;
第二个参数v -> v表示选择将原来的对象作为map的value值;
第三个参数(v1, v2) -> v1中,如果v1与v2的key值相同,选择v1作为那个key所对应的value值

可参考:https://www.cnblogs.com/mazhichu/p/11983451.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谛仙0

本人已实现,编写不易

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值