关于java:Java基础-Stream流原理与用法总结

27次阅读

共计 4427 个字符,预计需要花费 12 分钟才能阅读完成。

Stream 简化元素计算;

一、接口设计

从 Java1.8 开始提出了 Stream 流的概念,偏重对于源数据计算能力的封装,并且反对序列与并行两种操作形式;仍旧先看外围接口的设计:

  • BaseStream:根底接口,申明了流治理的外围办法;
  • Stream:外围接口,申明了流操作的外围办法,其余接口为指定类型的适配;

根底案例:通过指定元素的值,返回一个序列流,元素的内容是字符串,并转换为 Long 类型,最终计算求和后果并返回;

System.out.println("sum1="+IntStream.of(1,2,3).sum());
System.out.println("sum2="+Stream.of("1", "2", "3").mapToLong(Long::parseLong).sum());

整个 Stream 处理过程上看能够分为三段:创立流、两头操作、最终操作,即多个元素值通过流计算最终获取到求和的后果;

二、创立操作

除了 Stream 提供的创立办法之外,在 Java1.8 中,很多容器类的办法都进行的扩大,提供了汇合元素转流的能力;

  • Stream 创立
Stream<Integer> intStream = Stream.of(1, 2) ;
  • Collection 创立
List<String> getList = Arrays.asList("hello","copy") ;
Stream<String> strStream = getList.stream() ;
  • Array 创立
Double[] getArray = new Double[]{1.1,2.2};
Stream<Double> douStream = Arrays.stream(getArray) ;

上述形式创立的 Stream 流默认都是串行序列,能够通过 Stream.isParallel 进行判断;执行 Stream.parallel 办法能够转为并行流;

三、两头操作

通常对于 Stream 的两头操作,能够视为是源的查问,并且是懈怠式的设计,对于源数据进行的计算只有在须要时才会被执行,与数据库中视图的原理类似;

Stream 流的弱小之处便是在于提供了丰盛的两头操作,相比汇合或数组这类容器,极大的简化源数据的计算复杂度,案例中应用的数据结构如下;

public class TesStream {public static void main(String[] args)  {List<User> userList = getUserList () ;
    }
    private static List<User> getUserList (){List<User> userList = new ArrayList<>() ;
        userList.add(new User(1,"张三","上海")) ;
        userList.add(new User(2,"李四","北京")) ;
        userList.add(new User(3,"王五","北京")) ;
        userList.add(new User(4,"顺六","上海, 杭州")) ;
        return userList ;
    }
}
  • filter:过滤,输入 id 大于 1 的用户;
userList.stream().filter(user -> user.getId()>1).forEach(System.out::println);
  • map:将现有的元素转换映射到对应的后果,输入用户所在城市;
userList.stream().map(user -> user.getName()+"在"+user.getCity()).forEach(System.out::println);
  • peek:对元素进行遍历解决,每个用户 ID 加 1 输入;
userList.stream().peek(user -> user.setId(user.getId()+1)).forEach(System.out::println);
  • flatMap:数据拆分一对多映射,用户所在多个城市;
userList.stream().flatMap(user -> Arrays.stream(user.getCity().split(","))).forEach(System.out::println);
  • sorted:指定属性排序,依据用户 ID 倒序输入;
userList.stream().sorted(Comparator.comparingInt(User::getId).reversed()).forEach(System.out::println);
  • distinct:去重,用户所在城市去重后输入;
userList.stream().map(User::getCity).distinct().forEach(System.out::println);
  • skip & limit:截取,过滤后的数据跳过,截取第一条;
userList.stream().filter(user -> user.getId()>1).skip(1).limit(1).forEach(System.out::println);

相比于汇合与数组在 Java1.8 之前的解决逻辑,通过 Stream 流的办法简化对数据改、查、过滤、排序等一系列操作,下面对于最终办法只波及了 foreach 遍历;

四、最终操作

Stream 流执行完最终操作之后,无奈再执行其余动作,否则会报状态异样,提醒该流曾经被执行操作或者被敞开,想要再次执行操作必须从新创立 Stream 流;

  • min:最小值,获取用户最小的 id 值;
int min = userList.stream().min(Comparator.comparingInt(User::getId)).get().getId();
  • max:最大值,获取用户最大的 id 值;
int max = userList.stream().max(Comparator.comparingInt(User::getId)).get().getId();
  • sum:求和,对用户 ID 进行累计求和;
int sum = userList.stream().mapToInt(User::getId).sum() ;
  • count:总数,id 小于 2 的用户总数;
long count = userList.stream().filter(user -> user.getId()<2).count();
  • foreach:遍历,输入北京相干的用户;
userList.stream().filter(user -> "北京".equals(user.getCity())).forEach(System.out::println);
  • findAny:查找符合条件的任意一个元素,获取一个北京用户;
User getUser = userList.stream().filter(user -> "北京".equals(user.getCity())).findAny().get();
  • findFirst:获取符合条件的第一个元素;
User getUser = userList.stream().filter(user -> "北京".equals(user.getCity())).findFirst().get();
  • anyMatch:匹配判断,判断是否存在深圳的用户;
boolean matchFlag = userList.stream().anyMatch(user -> "深圳".equals(user.getCity()));
  • allMatch:全副匹配,判断所有用户的城市不为空;
boolean matchFlag = userList.stream().allMatch(user -> StrUtil.isNotEmpty(user.getCity()));
  • noneMatch:全不匹配,判断没有用户的城市为空;
boolean matchFlag = userList.stream().noneMatch(user -> StrUtil.isEmpty(user.getCity()));

这里只是演示一些简略的最终办法,次要波及 Stream 流的一些统计和判断相干的能力,在一些理论的业务利用中,显然这些性能还远远不够;

五、Collect 收集

Collector:后果收集策略的外围接口,具备将指定元素累加寄存到后果容器中的能力;并在 Collectors 工具中提供了 Collector 接口的实现类;

  • toList:将用户 ID 寄存到 List 汇合中;
List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ;
  • toMap:将用户 ID 和 Name 以 Key-Value 模式寄存到 Map 汇合中;
Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
  • toSet:将用户所在城市寄存到 Set 汇合中;
Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet());
  • counting:符合条件的用户总数;
long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());
  • summingInt:对后果元素即用户 ID 求和;
Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;
  • minBy:筛选元素中 ID 最小的用户
User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;
  • joining:将用户所在城市,以指定分隔符链接成字符串;
String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));
  • groupingBy:按条件分组,以城市对用户进行分组;
Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));

在代码工程中会波及到诸多的汇合数据计算的逻辑,尤其在微服务场景中,VO 数据模型须要对多个服务的数据进行组装,通过 Collector 能够极大精简组装过程;

$$End$$

正文完
 0