java8学习(五)Stream API

1。Steam流式思想概述

注意:Stream和IO流(InputStream/OutputStream)没有任何关系。
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。

2.Stream流的获取方式

2.1根据Collection获取

java.util.Collection 接口中加入了default方法 stream,也就是说Collection接口下的所有的实现都可以通过steam方法来获取Stream流。

public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.stream();
        Set<String> set=new HashSet<>();
        set.stream();
        Vector<String> vector=new Vector<>();
        vector.stream();
        //Map接口别没有实现Collection接口,这时我们可以根据Map获取对应的keyvalue的集合。
        Map<String,Object> map = new HashMap<>(); 
        Stream<String> stream = map.keySet().stream(); // key 
        Stream<Object> stream1 = map.values().stream(); // value 
        Stream<Map.Entry<String, Object>> stream2 = map.entrySet().stream(); // entry
    }
2.2通过Stream的of方法
public static void main(String[] args) {
        getStream2();
    }

    private static void getStream2(){
        String [] strArr={"1","a","b"};
        Stream.of(strArr).forEach(System.out::println);
        Integer [] arr={1,2,3,4,5};
        Stream.of(arr).forEach(System.out::println);
        int [] arr2={1,2,3,4};
        Stream.of(arr2).forEach(System.out::println);
    }

控制台输出:

1
2
3
4
5
[I@404b9385
1
a
b

可以看出基本数据类型的数组是不能通过Stream.of()获取到Stream的。

2.3Stream的常用方法

Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
终结方法:返回值类型不再是 Stream 类型的方法,不再支持链式调用。
终结方法包括:
count 、forEach 等。
非终结方法:返回值类型仍然是 Stream 类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结方法。)
Stream注意事项

  1. Stream只能操作一次
  2. Stream方法返回的是新的流
  3. Stream不调用终结方法,中间的操作不会执行
2.3.1 forEach(用来遍历流中的数)

接口:

void forEach(Consumer<? super T> action);

该方法接受一个Consumer接口,会将每一个流元素交给函数处理
使用:

public static void main(String[] args) {
        forEachTest();
    }

    /**
     * 循环遍历
     */
    private static void forEachTest(){
        List<String> strings = Arrays.asList("a", "b", "c");
        strings.forEach(System.out::println);
    }

控制台输出:

a
b
c

2.3.2 count(统计元素个数)

接口:

long count();

使用:

    public static void main(String[] args) {
       countTest();
   }

   private static void countTest(){
       long count = Stream.of(1, 2, 3, 4, 5).count();
       System.out.println("Stream中的元素个数为:"+count);
   }

控制台输出:

Stream中的元素个数为:5

2.3.3 filter(过滤数据返回符合条件的数据)

接口:

Stream<T> filter(Predicate<? super T> predicate);

接收一个Predicate函数式接口参数作为筛选条件,可以通过filter方法将一个流转换成另一个子集流。
使用:

    public static void main(String[] args) {
       filterTest();
   }

   private static void filterTest(){
       Stream.of(1,2,3,4,5).filter(s->s>2).forEach(System.out::println);
   }

控制台输出:

3
4
5

2.3.4 limit(对流进行截取处理,截取前n个数据)

接口:

Stream<T> limit(long maxSize);

使用:

public static void main(String[] args) {
       limitTest();
   }

   private static void limitTest(){
       Stream.of(1,2,3,4,5).limit(2).forEach(System.out::println);
   }

控制台输出:

1
2

2.3.5 skip(从第n位开始截取数据)

接口:

Stream<T> skip(long n);

使用:

public static void main(String[] args) {
       skipTest();
   }

   private static void skipTest(){
       Stream.of(1,2,3,4,5).skip(2).forEach(System.out::println);
   }

控制台输出:

3
4
5

2.3.6 map(要将流中的元素映射到另一个流中)
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

使用:

    public static void main(String[] args) {
      mapTest();
  }

  private static void mapTest(){
      Stream.of("a","b").map(String::toUpperCase).forEach(System.out::println);
  }

控制台输出:

A
B

2.3.7 sorted (排序)

接口:

    Stream<T> sorted();
   Stream<T> sorted(Comparator<? super T> comparator);

使用:

    public static void main(String[] args) {
       sortedTest();
   }

   private static void sortedTest(){
       //按自然顺序排序
       Stream.of(1, 4, 2, 5, 3).sorted().forEach(System.out::println);
       //自定义排序
       Stream.of(1,4,2,5,3).sorted((o1, o2) -> o2-o1).forEach(System.out::println);
   }

控制台输出:略

2.3.7 distinct(去重复)

接口

    public static void main(String[] args) {
       distinctTest();
   }

   private static void distinctTest(){
       Stream.of("a","b","a","c").distinct().forEach(System.out::println);
       Stream.of(
               new UserDto(1l,"张三"),
               new UserDto(1l,"张三"),
               new UserDto(3l,"李四"),
               new UserDto(4l,"王五")
       ).distinct().forEach(System.out::println);
   }

控制台输出:

a
b
c
UserDto{id=1, userName=‘张三’}
UserDto{id=1, userName=‘张三’}
UserDto{id=3, userName=‘李四’}
UserDto{id=4, userName=‘王五’}

这时候可以看到我们自定义的类型是没有过滤到重复值的,我们需要重写hashCode和equals方法来去重,即:
UserDto 重写hashCode和equals方法:

public class UserDto {

    private Long id;

    private String userName;


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public UserDto(Long id, String userName) {
        this.id = id;
        this.userName = userName;
    }

    @Override
    public String toString() {
        return "UserDto{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserDto userDto = (UserDto) o;
        return Objects.equals(id, userDto.id) && Objects.equals(userName, userDto.userName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, userName);
    }
}

测试

    public static void main(String[] args) {
       distinctTest();
   }

   private static void distinctTest(){
       Stream.of("a","b","a","c").distinct().forEach(System.out::println);
       Stream.of(
               new UserDto(1l,"张三"),
               new UserDto(1l,"张三"),
               new UserDto(3l,"李四"),
               new UserDto(4l,"王五")
       ).distinct().forEach(System.out::println);
   }

控制台输出:

a
b
c
UserDto{id=1, userName=‘张三’}
UserDto{id=3, userName=‘李四’}
UserDto{id=4, userName=‘王五’}

2.3.8 match(判断数据是否匹配指定的条件)

接口:

boolean anyMatch(Predicate<? super T> predicate);

boolean allMatch(Predicate<? super T> predicate);

boolean noneMatch(Predicate<? super T> predicate);

使用:

    public static void main(String[] args) {
        matchTest("张");
    }

    private static void matchTest(String msg){
        boolean b = Stream.of("张", "王", "李").anyMatch(s -> s.equals(msg));
        System.out.println("元素中是否有任意一个满足条件是否成立:"+b);
        boolean b1 = Stream.of("张", "王", "李").allMatch(s -> s.equals(msg));
        System.out.println("元素中都满足条件是否成立:"+b1);
        boolean b2 = Stream.of("张", "王", "李").noneMatch(s -> s.equals(msg));
        System.out.println("元素中都不满足条件是否成立:"+b2);
    }

控制台输出:

元素中是否有任意一个满足条件是否成立:true
元素中都满足条件是否成立:false
元素中都不满足条件是否成立:false

2.3.9 find(查找某些元素)

接口:

Optional<T> findFirst();
Optional<T> findAny();

使用:

    public static void main(String[] args) {
        findTest();
    }

    private static void findTest() {
        String s1 = Stream.of("张三", "张三飞", "李四", "王五")
                .filter(msg->msg.startsWith("张"))
                .findFirst().get();
        String s2 = Stream.of("张三", "张三飞", "李四", "王五")
                .filter(msg->msg.startsWith("张"))
                .findAny().get();
        System.out.println("s1:"+s1+"---s2:"+s2);

    }

这时候会发现,findFirst与findAny返回的都是第一个元素的结果,但是不符合API给出的理论,按道理讲findAny应该是返回其中的任意一个,这时候发现了流有:
串行流:在一个线程在处理业务。
并行流:是会有多个线程来并发处理业务。
那么我们来用并行流测试一下:

    public static void main(String[] args) {
       findTest();
   }

   private static void findTest() {

       List<String> list1 = Arrays.asList("张三", "张三飞", "李四", "王五");
       String s3=list1.parallelStream().filter(msg->msg.startsWith("张"))
               .findFirst().get();
       String s4=list1.parallelStream().filter(msg->msg.startsWith("张"))
               .findAny().get();
       System.out.println("并行流操作 s3:"+s3+"---s4:"+s4+"");

       String s1 = Stream.of("张三", "张三飞", "李四", "王五")
               .filter(msg->msg.startsWith("张"))
               .findFirst().get();
       String s2 = Stream.of("张三", "张三飞", "李四", "王五")
               .filter(msg->msg.startsWith("张"))
               .findAny().get();
       System.out.println("串行流操作 s1:"+s1+"---s2:"+s2);

   }

控制台输出:

并行流操作 s3:张三—s4:张三飞
串行流操作 s1:张三—s2:张三

所以得出结论,如果是串行流的话,findAny是返回第一个,如果是并行流会返回任意一个。

2.3.10 max和min (最大值、最小值)

接口:

Optional<T> max(Comparator<? super T> comparator);

Optional<T> min(Comparator<? super T> comparator);

使用:

    public static void main(String[] args) {
        maxAndMinTest();
    }
    private static void maxAndMinTest(){
        Integer max = Stream.of(1, 2, 3, 4, 5).max((o1, o2) -> o1 - o2).get();
        System.out.println("最大值:"+max);
        Integer min = Stream.of(1, 2, 3, 4, 5).min((o1, o2) -> o1 - o2).get();
        System.out.println("最小值:"+min);
    }

控制台输出:

最大值:5
最小值:1

2.3.11 reduce (数据归纳得到一个数据)

接口:

T reduce(T identity, BinaryOperator<T> accumulator);

使用:

      reduceTest();
  }

  private static void reduceTest(){
      //reduce(0, (x, y) -> x + y)
      //0 是一个默认值
      //第一次的时候会将默认值赋给x,后续是将上一次操作的结果赋值给x
//        Integer reduce = Stream.of(1, 2, 3, 4, 5).reduce(0, (x, y) -> x + y);
      Integer reduce = Stream.of(1, 2, 3, 4, 5)
              .reduce(0, (x, y) ->{
                      System.out.println("x:"+x+"  y"+y);
                      return x + y;
              });
      System.out.println(reduce);
  }

控制台输出:

x:0 y1
x:1 y2
x:3 y3
x:6 y4
x:10 y5
15

2.3.12 concat(将两个流合并成一个流)

接口:

    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
     Objects.requireNonNull(a);
     Objects.requireNonNull(b);

     @SuppressWarnings("unchecked")
     Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
             (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
     Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
     return stream.onClose(Streams.composedClose(a, b));
 }

使用:

    public static void main(String[] args) {
        concatTest();
    }

    private static void concatTest(){
        Stream<String> i = Stream.of("1", "2");
        Stream<String> a = Stream.of("a", "b");
        Stream.concat(i,a).forEach(System.out::println);
    }  

控制台输出:

1
2
a
b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值