介绍
Java8中有两大最为重要的改变。第一个是 Lambda 表达式; 另外一个则是 Stream API(java.util.stream.*)
。
Stream是 Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用 Stream API 对集合数据进行操作,就类似于使用 SQL执行的数据库查询。也可以使用Stream API来并行执行操作简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
流(Stream)到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是致据遏进的是让算*”
注意:
Stream 自己不会存储元素。
Stream 不会改变源对象。相反,他们会返回一个持有结果的新 Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
生成 Stream
1/4 Collection体系集合
使用默认方法 stream()
生成流, default Stream<E> stream()
List<String> list = new ArrayList<String>(); Stream<String> listStream = list.stream(); Set<String> set = new HashSet<String>(); Stream<String> setStream = set.stream();
2/4 Map体系集合
把Map转成Set集合,间接的生成流
Map<String,Integer> map = new HashMap<String, Integer>(); Stream<String> keyStream = map.keySet().stream(); Stream<Integer> valueStream = map.values().stream(); Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
3/4 数组
通过Arrays中的静态方法stream生成流
String[] strArray = {"hello","world","java"}; Stream<String> strArrayStream = Arrays.stream(strArray);
4/4 同种数据类型的多个数据
通过Stream接口的静态方法of(T… values)生成流
Stream<String> strArrayStream2 = Stream.of("hello", "world", "java"); Stream<Integer> intStream = Stream.of(10, 20, 30);
Stream 流的中间操作
筛选与切片
- 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
- filter:接收Lambda,从流中筛选出满足条件的元素。
过滤数据
// 留下满足条件的
Stream<T> filter(Predicate predicate)
Stream<T> stream = list.stream().filter(s -> s.startsWith("张"));
跳过(不要前几个)
Stream<T> skip(long n)
Stream<String> s2 = list.stream().skip(2);
截取(只取前几个)
Stream<T> limit(long maxSize)
Stream<T> stream = list.stream().limit(3);
实现分页
Integer currentPage = 3; Integer pageSize = 10; List<Integer> collect = list.stream().skip( (currentPage - 1) * pageSize ).limit(pageSize).collect(Collectors.toList());
合并
static Stream concat(Stream a, Stream b)
Stream.concat(s1,s2);
去重
筛选,通过流所生成元素的hashcode()和equals()去除重复元素,要想实现成功,必须实体类实现重写这两个方法!
Stream distinct()
list.stream().distinct();
Stream流终结操作方法
对此流的每个元素执行操作
void forEach(Consumer action)
list.stream().forEach(System.out::println);
返回此流中的元素数
long count()
long count = list.stream().count(); System.out.println(count);
Stream流的收集操作
List<String> names = listStream.collect(Collectors.toList()); Set<Integer> set = stream.collect(Collectors.toSet()); Map<Integer, String> map = stream.collect(Collectors.toMap(s -> s, s -> 2 * s + ""));
求和
如果是 double 类型 注意会遇到精度问题。so 不建议 double 类型的用这个方法。
long sum = list.stream().mapToLong(e -> e /** 可以指定具体字段 */).sum();
List<Project> list = projectService.list(queryWrapper); // 总投资数 Long totalInvestment = list.stream().mapToLong(Project::getTotalInvestment).sum();
实操
将集合中的某一列拿出来组合成新的集合
List<Integer> idList = userList.stream().map(OrderUser::getPlatformUserId) .collect(Collectors.toList());
List 转 Set
Set<Integer> idSet = resourceObjectIdList.stream().collect(Collectors.toSet());
映射
map:接收Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
List<Integer> list = Arrays.asList(13, 23, 99, 1889, 87, 1000, 88, 2, 99); List<Integer> collect = list.stream().map(i -> i + 1).collect(Collectors.toList()); // [14, 24, 100, 1890, 88, 1001, 89, 3, 100]
集合复制
List<CompanyChecks> checksList = //; List<CompanyChecksNameVO> checksNameVOList = checksList.stream() .map(p -> { CompanyChecksNameVO vo = new CompanyChecksNameVO(); BeanUtils.copyProperties(p, vo); return vo; }).collect(Collectors.toList());
排序
public void test(){ //自然排序 List<String> list = Arrays.asList("aaa", "eee", "ddd", "bbb"); list.stream().sorted().forEach(System.out::println); //定制排序 List<Person> list1 = Arrays.asList( new Person("张三", 18, 2000.0), new Person("李四", 18, 5000.0), new Person("王五", 45, 8700.0), new Person("赵六", 42, 4200.0), new Person("陈七", 56, 13100.0) ); list1.stream().sorted((p1,p2) -> { if (p1.getAge().equals(p2.getAge())){ return p1.getSale().compareTo(p2.getSale()); }else { return p1.getAge().compareTo(p2.getAge()); } }).forEach(System.out::println); }
List<Integer> list = Arrays.asList(13, 23, 99, 1889, 87, 1000, 88, 2, 99); // 默认 顺序 List<Integer> collect = list.stream().sorted().collect(Collectors.toList()); // [2, 13, 23, 87, 88, 99, 99, 1000, 1889] // 定制排序:倒序 List<Integer> collect = list.stream().sorted((v1, v2) -> v2 - v1).collect(Collectors.toList()); // [1889, 1000, 99, 99, 88, 87, 23, 13, 2]
根据特定字段排序
正序
records = records.stream() .sorted(Comparator.comparing(StudyReview::getReviewDate)) .collect(Collectors.toList());
倒序
records = records.stream() .sorted(Comparator.comparing(StudyReview::getReviewDate).reversed()) .collect(Collectors.toList());
多个字段排序
list.stream().sorted(Comparator.comparing(User::getAge) .thenComparing(User::getId) .reversed()) .forEach(System.out::println);