- stream:
- 是数据渠道,用于操作数据源(数组,集合等.)所产生的元素序列
- 集合讲的是数据,流讲的是计算.
- 并行: parallel 使用并行流要注意线程安全问题.- Collections.synchronizedList
- 注意:
- stram 自己不会存储元素.
- stream 不会改变源对象,相反 他们会返回一个持有结果的新stream.
- stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才执行.
- 使用步骤:
- 1.创建stream
- 2.中间操作
- 3.终止操作
- 注意:中间操作 不会执行任何操作,只有在终止操作的时候才会一次性执行.
- 多个中间操作可以连接起来形成一个流水线,除非流水线上出发终止操作,否则中间操作不会执行任何处理.而在终止操作时一次性全部处理.称为 "惰性求值".
-
public static void main(String[] args) { //可以通过Collection系列集合提供的stream() 串行 或 parallelStream() 并行 List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); //通过Arrays中的静态方法stream()获取 数组流 LoginRequest[] loginRequests = new LoginRequest[10]; Stream<LoginRequest> stream1 = Arrays.stream(loginRequests); //通过stream类中的静态方法of() Stream<String> aa = Stream.of("aa"); //创建 无限流 //迭代 Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2); //iterate.limit(10) 就是中间操作 //forEach(System.out::println) 就是终止操作 iterate.limit(10).forEach(System.out::println); } //并行流 parallelStream public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for (int j = 0; j < 1000; j++) { list.add(j); } System.out.println("最开始生成的集合长度:"+list.size()); //parallelStream遍历数据的时候会产生丢失的问题 for (int i = 0; i < 10 ; i++) { List<Integer> parseList = new ArrayList<>(); List<Integer> synchronizedList = Collections.synchronizedList(parseList); list.parallelStream().forEach(integer -> { synchronizedList.add(integer); }); System.out.println("每次遍历的集合长度:"+ synchronizedList.size()); } }
-
中间操作:
-
筛选与切片
-
filter 接收lambda, 从六中排除某些元素
-
limit 截断流.使其元素不超过给定数量
-
skip(n) 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit互补
-
distinct 筛选(去重),通过流所生成元素的hashCode()和equals()去除重复元素
-
-
filter 筛选:
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); /** * @Description: filter 筛选 * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { Stream<LoginRequest> loginRequestStream = loginRequests.stream().filter((e) -> "22".equals(e.getAge())); loginRequestStream.forEach(System.out::println); }
-
-
limit截断:
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); /** * @Description: limit截断 * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { loginRequests.stream() .filter((e) -> Integer.valueOf(e.getAge()) > 11) .limit(2) .forEach(System.out::println); } 控制台: LoginRequest{userName='李四', passWord='2222', age='22'} LoginRequest{userName='王五', passWord='3333', age='33'}
-
-
skip 跳过:
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); /** * @Description: skip 跳过 * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { loginRequests.stream() .filter((e) -> Integer.valueOf(e.getAge()) > 11) .skip(2) .forEach(System.out::println); } 控制台: LoginRequest{userName='赵六', passWord='6666', age='66'}
-
-
distinct 去重
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("张三", "1111", "11"), new LoginRequest("张三", "1111", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); /** * @Description: distinct 去重 * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { loginRequests.stream() .filter((e) -> Integer.valueOf(e.getAge()) > 1) .distinct() .forEach(System.out::println); } 要重写对象的equals和hashCode方法. 控制台: LoginRequest{userName='张三', passWord='1111', age='11'} LoginRequest{userName='李四', passWord='2222', age='22'} LoginRequest{userName='王五', passWord='3333', age='33'} LoginRequest{userName='赵六', passWord='6666', age='66'}
-
-
-
映射:
-
map 接受lambda,讲元素转成其他形式或提取信息,接受一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素.
-
flagMap 接收一个函数作为参数,将流中的每一个值都转换成另一个流,然后把所有的流了解成一个流.
-
/** * @Description: 映射 map * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd"); list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println); } 控制台: AAA BBB CCC DDD /** * @Description: 映射 flatMap * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println); System.out.println("----------------------------------"); //正常的map取值 Stream<Stream<Character>> streamStream = list.stream().map(Test::filter); //使用flatMap 都放到flagMap中 Stream<Character> characterStream = list.stream().flatMap(Test::filter); characterStream.forEach(System.out::println); } public static Stream<Character> filter(String string) { List<Character> list = new ArrayList(); for (Character character : string.toCharArray()) { list.add(character); } return list.stream(); } 总结:map相当于把一个个流加到map这个大流中. flatMap 相当于把流中的一个个元素加到flatMap流中
-
-
排序:
-
sorted() 自然排序
-
sorted(Comparator com) 定制排序
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("张三1", "1113", "11"), new LoginRequest("张三2", "1112", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); static List<String> list = Arrays.asList("aaa", "ccc", "ddd", "bbb"); /** * @Description: 排序 sorted * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { list.stream().sorted().forEach(System.out::println); //控制台 aaa bbb ccc ddd loginRequests.stream().sorted((x, y) -> { //年龄相同 比密码 if (x.getAge().equals(y.getAge())) { return x.getPassWord().compareTo(y.getPassWord()); } else { //直接比年龄 return Integer.valueOf(x.getAge()).compareTo(Integer.valueOf(y.getAge())); //倒叙 return -Integer.valueOf(x.getAge()).compareTo(Integer.valueOf(y.getAge())); } } ).forEach(System.out::println); } 控制台: LoginRequest{userName='张三', passWord='1111', age='11'} LoginRequest{userName='张三2', passWord='1112', age='11'} LoginRequest{userName='张三1', passWord='1113', age='11'} LoginRequest{userName='李四', passWord='2222', age='22'} LoginRequest{userName='王五', passWord='3333', age='33'} LoginRequest{userName='赵六', passWord='6666', age='66'}
-
-
终止:
-
查找与匹配:
-
allMatch 检查是否匹配所有元素
-
anyMatch 检查是否至少匹配一个元素
-
noneMatch 检查是否没有匹配的所有元素
-
findFirst 返回第一个元素
-
finaAny 返回当前流中的任意元素
-
count 返回流中元素的总个数
-
max 返回流中最大值
-
min 返回流中最小值
-
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("张三1", "1113", "11"), new LoginRequest("张三2", "1112", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); /** * @Description: 查找匹配 * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { boolean b = loginRequests.stream().allMatch((x) -> x.getPassWord().equals("111111")); System.out.println(b); //其余的匹配用法基本相同 //findFirst Optional<LoginRequest> optional = loginRequests.stream().sorted((x, y) -> x.getAge().compareTo(y.getAge())).findFirst(); //Optional是为了放置空指针 如果为空就用orElse()括号里面的. LoginRequest loginRequest1 = new LoginRequest("111", "222", "333"); LoginRequest loginRequest = optional.orElse(loginRequest1); System.out.println(loginRequest.toString()); } 控制台: false LoginRequest{userName='张三', passWord='1111', age='11'}
-
-
归约 reduce(T identity,BinaryOperator ) / reduct(BinaryOperator) 可以将流中元素反复结合起来,得到一个值.
-
/** * @Description: 归约 reduce * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Integer reduce = list.stream().reduce(0, (x, y) -> x + y); System.out.println(reduce); System.out.println("================================"); //有可能返回为空的都是Optional ,因为上面指定了起始值.不可能为空. Optional<String> reduce1 = loginRequests.stream().map(LoginRequest::getUserName).reduce((x, y) -> x += (y)); System.out.println(reduce1); } 控制台: 15 ================================ Optional[张三张三1张三2李四王五赵六]
-
-
收集: collect 将流转换为其他形式,接受一个collector接口的实现,用于给stream中元素做汇总的方法. (分组)
-
static List<LoginRequest> loginRequests = Arrays.asList( new LoginRequest("张三", "1111", "11"), new LoginRequest("张三1", "1113", "11"), new LoginRequest("张三2", "1112", "11"), new LoginRequest("李四", "2222", "22"), new LoginRequest("王五", "3333", "33"), new LoginRequest("赵六", "6666", "66") ); static List<String> list = Arrays.asList("aaa", "ccc", "ddd", "bbb"); /** * @Description: 收集 collect * @Param: [args] * @return: void * @Author: 单人影 * @Date: 2019/12/8 0008 15:59 */ public static void main(String[] args) { List<String> collect = loginRequests.stream().map(LoginRequest::getUserName).collect(Collectors.toList()); System.out.println(collect.toString()); Set<String> collects= loginRequests.stream().map(LoginRequest::getAge).collect(Collectors.toSet()); System.out.println(collects.toString()); //分组 groupingBy 还可以多级分组 Map<String, List<LoginRequest>> collect1 = loginRequests.stream().collect(Collectors.groupingBy(LoginRequest::getAge)); System.out.println(collect1.toString()); //还可以分区.true一个区 false一个区 Collectors.partitioningBy //连接 Collectors.join() 可以写成join(",") 逗号拼接 } 控制台: [张三, 张三1, 张三2, 李四, 王五, 赵六] [11, 22, 33, 66] {66=[LoginRequest{userName='赵六', passWord='6666', age='66'}], 33=[LoginRequest{userName='王五', passWord='3333', age='33'}], 22=[LoginRequest{userName='李四', passWord='2222', age='22'}], 11=[LoginRequest{userName='张三', passWord='1111', age='11'}, LoginRequest{userName='张三1', passWord='1113', age='11'}, LoginRequest{userName='张三2', passWord='1112', age='11'}]}
-
- 是数据渠道,用于操作数据源(数组,集合等.)所产生的元素序列
- 使用示例:
-
list累加 BigDecimal allAssets = tradeBalanceCrmList.stream().filter(item -> item.getTotalProfit() != null).map(TradeBalanceCrmDto::getTotalProfit).reduce(BigDecimal.ZERO, BigDecimal::add); 分组 Map<String, List<TradeBalanceCrmDto>> productTypeGroupBy = tradeBalanceCrmList.stream().filter(item -> StringUtils.isNotEmpty(item.getProductType())).collect(Collectors.groupingBy(TradeBalanceCrmDto::getProductType)); 遍历 for (String key : productTypeGroupBy.keySet()) { if (ProductTypeEnum.PUBLICFUND.getCode().equals(key)) { publicList.addAll(productTypeGroupBy.get(key)); log.debug("公募:{},value:{}", productTypeGroupBy.get(key)); } else if (ProductTypeEnum.PRIVATEFUND.getCode().equals(key)) { privateList.addAll(productTypeGroupBy.get(key)); log.debug("似募:{},value:{}", productTypeGroupBy.get(key)); } } 排序: Collections.sort(tradeAppFlowDtos, (o1, o2) -> o2.getAcceptTime().compareTo(o1.getAcceptTime())); 如果要按照升序排序, 则o1 小于o2,返回-1(负数),相等返回0,01大于02返回1(正数) 如果要按照降序排序 则o1 小于o2,返回1(正数),相等返回0,01大于02返回-1(负数) 去除为空字段.返回list List<CustManagerInfo> collect = custManagerInfos.stream().filter((item) -> StringUtils.isNotEmpty(item.getFundManagerCode())).collect(Collectors.toList());
-
双层for循环:
-
List<TradeBalanceCrmDto> tradeBalanceCrmDtos = tradeBalanceCrmExtendMapper.selectByConditionByCustId(custId); if (CollectionUtils.isEmpty(tradeBalanceCrmDtos)) { return tradeBalanceCrmDtos; } List<TradeBalanceCrmDto> list = new ArrayList<>(); TradeBalanceCrmDto tradeBalanceCrmDtoResult = null; for (TradeBalanceCrmDto tradeBalanceCrmDto : tradeBalanceCrmDtos) { boolean flag = list.stream().anyMatch(item -> item.getFundCode().equals(tradeBalanceCrmDto.getFundCode())); if (flag) { continue; } tradeBalanceCrmDtoResult = new TradeBalanceCrmDto(); BeanUtils.copyProperties(tradeBalanceCrmDto, tradeBalanceCrmDtoResult); List<TradeBalanceCrmDto> collect = tradeBalanceCrmDtos.stream().filter((item) -> tradeBalanceCrmDto.getFundCode().equals(item.getFundCode())).collect(Collectors.toList()); log.debug("归集的List为:{}", collect.toString()); tradeBalanceCrmDtoResult.setFundAsset(collect.stream().filter((item) -> item.getFundAsset() != null).map(TradeBalanceCrmDto::getFundAsset).reduce(BigDecimal.ZERO, (x, y) -> x.add(y))); tradeBalanceCrmDtoResult.setTotalBala(collect.stream().filter((item) -> item.getTotalBala() != null).map(TradeBalanceCrmDto::getTotalBala).reduce(BigDecimal.ZERO, (x, y) -> x.add(y))); tradeBalanceCrmDtoResult.setAvailBala(collect.stream().filter((item) -> item.getAvailBala() != null).map(TradeBalanceCrmDto::getAvailBala).reduce(BigDecimal.ZERO, (x, y) -> x.add(y))); tradeBalanceCrmDtoResult.setTotalProfit(collect.stream().filter((item) -> item.getTotalProfit() != null).map(TradeBalanceCrmDto::getTotalProfit).reduce(BigDecimal.ZERO, (x, y) -> x.add(y))); list.add(tradeBalanceCrmDtoResult); }
-
-
-
list 大批量数据处理 分组
-
// 1.java8 Stream 大数据量List分批处理 //按每50个一组分割 private static final Integer MAX_NUMBER = 2; /** * 计算切分次数 */ private static Integer countStep(Integer size) { return (size + MAX_NUMBER - 1) / MAX_NUMBER; } public static void main(String[] args) { List<String> list = Arrays.asList('1', '2', '3', '4', '5', '6','7'); int limit = countStep(list.size()); //方法一:使用流遍历操作 List<List<String>> mglist = new ArrayList<>(); Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> { mglist.add(list.stream().skip(i * MAX_NUMBER).limit(MAX_NUMBER).collect(Collectors.toList())); }); System.out.println(mglist); //方法二:获取分割后的集合 List<List<String>> splitList = Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a -> list.stream().skip(a * MAX_NUMBER).limit(MAX_NUMBER).parallel().collect(Collectors.toList())).collect(Collectors.toList()); System.out.println(splitList); } // 2.使用google guava对List进行分割 //按每50个一组分割 List<List<String>> parts = Lists.partition(list , 50); // 3.使用apache common collection List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); List<List<Integer>> subs = ListUtils.partition(intList, 3); // 4.手写代码算 public static <T> List<List<T>> averageAssign(List<T> source, int n) { List<List<T>> result = new ArrayList<>(); //(先计算出余数) int remainder = source.size() % n; //然后是商 int number = source.size() / n; //偏移量 int offset = 0; for (int i = 0; i < n; i++) { List<T> value; if (remainder > 0) { value = source.subList(i * number + offset, (i + 1) * number + offset + 1); remainder--; offset++; } else { value = source.subList(i * number + offset, (i + 1) * number + offset); } result.add(value); } return result; }
-
常用实例:
-
//过滤不为空的list List<CustManagerInfo> collect = custManagerInfos.stream().filter((item) -> StringUtils.isNotEmpty(item.getFundManagerCode())).collect(Collectors.toList()); //非空 分组 Map<String, List<TransferListVo>> registarCodeMap = list.stream().filter(item -> StringUtils.isNotEmpty(item.getRegistrarCode())).collect(Collectors.groupingBy(TransferListVo::getRegistrarCode)); //非空 累加 BigDecimal allAssets = tradeBalanceCrmList.stream().filter(item -> item.getTotalProfit() != null).map(TradeBalanceCrmDto::getTotalProfit).reduce(BigDecimal.ZERO, BigDecimal::add); //取对象的某个字段 拼接成字符串 String fundCodes = responseList.stream().map(r -> r.getFundCode()).collect(Collectors.joining(",")); //字符串逗号份额 变成list List<String> collect2 = Arrays.stream(fundCodes.split(",")).collect(Collectors.toList()); //list排序 response.getStateList().sort(Comparator.comparingInt(o -> (Integer.parseInt((o.getCustNo()))))); //分批处理 /** * 分批次查询 50条一次 */ private final int MAX_NUMBER = 50; List<List<String>> partition = Lists.partition(fundCodes, MAX_NUMBER); //正序 Collections.sort(this.arrayList); //倒叙 Collections.sort(this.arrayList, Collections.reverseOrder()); //过滤 List<ImportIaFundInfoVo> filterList = importIaFundInfoVos.stream().filter((item) -> StringUtils.isNotEmpty(item.getFundCode())).collect(Collectors.toList()); // importIaFundInfoVos 根据 基金代码 去重 List<ImportIaFundInfoVo> collect = filterList.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(ImportIaFundInfoVo::getFundCode))), ArrayList::new)); // anyMatch boolean aa = strs.stream().anyMatch(str -> str.equals("a")); // 对象属性逗号拼接 去重 iaClientRequest.setCombineManagers(pageInfo.getList().stream().map(IaSignFlow::getChannelType).distinct().collect(Collectors.joining(","))); //list 转list 然后根据某个主键 变成Map<String, IaClientConfigDTO> 主键对象的形式 Map<String, IaClientConfigDTO> collect = BeanUtil.copyListProperties(list, IaClientConfigDTO::new).stream().collect(Collectors.toMap(IaClientConfigDTO::getClientId, Function.identity(), (key1, key2) -> key2)); // 字符串过滤拼接 String tradeAccos = batchContractFlows.stream().map(BatchContractFlow::getTradeAcco) .filter(StringUtils::isNotEmpty).distinct().collect(Collectors.joining(",")); Map<String, CustomerEstablishAccountDTO> fofundNoMap = records.stream() .filter(item -> StringUtils.isNotEmpty(item.getFofundNo())) .collect(Collectors.toMap(CustomerEstablishAccountDTO::getFofundNo, Function.identity(), (key1, key2) -> key2)); //list按照某些属性 从另一个list中过滤不存在的数据 List<TradeConfirmUqKeyBO> noConfirm = params.getConfirmUqKey().stream(). filter(item -> confirmList.stream() .noneMatch(confirm -> StringUtils.equals(item.getConfirmNo(), confirm.getConfirmNo()) && StringUtils.equals(item.getFundCode(), confirm.getFundCode()) && StringUtils.equals(item.getConfirmDate(), confirm.getConfirmDate()))) .collect(Collectors.toList()); // list变map key多字段拼接 Map<String, TestData> map = list.stream().collect(Collectors.toMap(d -> d.getName() + "-" + d.getSex(), Function.identity(),(d1,d2) -> d1)); // list 两个字段合并到一个 list中 List<String> fundCodeList = pageDataOfPage.getRecords().stream().flatMap(d -> Stream.of(d.getFundCode(), d.getTargetFundCode())).distinct().collect(Collectors.toList());
-
java 1.8 Stream
于 2019-12-08 23:28:06 首次发布