数据准备
创建实体类Author
package com.zsh.stream.domain.po; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode// 用于后期的去重使用 public class Author { // id private Long id; // 姓名 private String name; // 年龄 private Integer age; // 简介 private String intro; // 作品 private List<Book> books; }
创建实体类Book
package com.zsh.stream.domain.po; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode// 用于后期的去重使用 public class Book { // id private Long id; // 书名 private String name; // 分类 private String category; // 评分 private Integer score; // 简介 private String Intro; }
创建测试类
package com.zsh.stream.demo; import com.zsh.stream.domain.po.Author; import com.zsh.stream.domain.po.Book; import java.util.*; import java.util.stream.Stream; public class StreamDemo { /** * 数据准备 * @return */ private static List<Author> getAuthors() { // 数据初始化 Author author1 = new Author(1L, "开朗觉觉", 16, "30年超级Java开发工程师", null); Author author2 = new Author(1L, "开朗觉觉", 16, "30年超级Java开发工程师", null); Author author3 = new Author(3L, "小美", 17, "10年超级Java开发工程师", null); Author author4 = new Author(4L, "觉觉", 19, "5年超级Java开发工程师", null); // 书籍列表 ArrayList<Book> books1 = new ArrayList<>(); ArrayList<Book> books2 = new ArrayList<>(); ArrayList<Book> books3 = new ArrayList<>(); books1.add(new Book(1L,"晨岛快速跑图攻略1","哲学",88,"123123")); books1.add(new Book(2L,"晨岛快速跑图攻略2","哲学",88,"123123")); books1.add(new Book(3L,"晨岛快速跑图攻略2","哲学",88,"123123")); books2.add(new Book(1L,"晨岛快速跑图攻略1","哲学",88,"123123")); books2.add(new Book(2L,"晨岛快速跑图攻略2","哲学",88,"123123")); books2.add(new Book(3L,"晨岛快速跑图攻略2","哲学",88,"123123")); books3.add(new Book(7L,"晨岛快速跑图攻略3","哲学",88,"123123")); books3.add(new Book(8L,"晨岛快速跑图攻略3","哲学",88,"123123")); books3.add(new Book(9L,"晨岛快速跑图攻略3","哲学",88,"123123")); author1.setBooks(books1); author2.setBooks(books2); author3.setBooks(books3); author4.setBooks(books3); ArrayList<Author> authorList = new ArrayList<>(Arrays.asList(author1,author2,author3,author4)); return authorList; } }
入门测试
打印年龄小于18的作家名字,并且去重
public class StreamDemo { public static void main(String[] args) { // 打印年龄小于18的作家名字,并且去重 test1(); } /** * 打印年龄小于18的作家名字,并且去重 */ private static void test1() { // 数据准备 List<Author> authors = getAuthors(); // 打印年龄小于18的作家名字,并且去重 authors.stream() // 把集合转换成流 // 去重 .distinct() // 筛选 .filter(author -> author.getAge() < 18) // 打印 .forEach(author -> System.out.println(author.getName())); } }
单列集合创建流(重要)
public class StreamDemo { public static void main(String[] args) { // 单列集合创建流(重要) test2(); } /** * 单列集合创建流 */ private static void test2() { // 数据准备 List<Author> authors = getAuthors(); // 单列集合创建流 Stream<Author> stream = authors.stream(); } }
数组创建流
public class StreamDemo { public static void main(String[] args) { // 数组创建流(方式1) test3(); // 数组创建流(方式2) test4(); } /** * 数组创建流(方式2) */ private static void test4() { // 创建数组 Integer[] numArr = {1,2,3,4,5}; // 数组创建流 Stream<Integer> stream = Stream.of(numArr); // 输出 stream.filter(integer -> integer > 2) .forEach(integer -> System.out.println(integer)); } /** * 数组创建流(方式1) */ private static void test3() { // 创建数组 Integer[] numArr = {1,2,3,4,5}; // 数组创建流 Stream<Integer> stream = Arrays.stream(numArr); // 输出 stream.filter(integer -> integer % 2 == 0) .forEach(integer -> System.out.println(integer)); } }
Map创建流
public class StreamDemo { public static void main(String[] args) { // Map创建流 test5(); } /** * Map创建流 */ private static void test5() { HashMap<String, Integer> map = new HashMap<>(); map.put("开朗觉觉",16); map.put("开朗莽莽",17); map.put("酪小美",18); // 将Map集合转换为Set集合 (Map集合是不能直接转换为Stream流的,所以要先转成Set集合) Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); // 创建Stream流 Stream<Map.Entry<String, Integer>> stream = entrySet.stream(); // 输出 stream.filter(item -> item.getValue() == 18) .forEach(item -> System.out.println(item.getKey() + "," + item.getValue() + "岁")); } }
中间操作常用方法
filter() 根据条件进行过滤
public class StreamCenter { public static void main(String[] args) { // filter() 打印所有名字长度大于2的作家姓名 test1(); } /** * filter() 打印所有名字长度大于2的作家姓名 */ private static void test1() { // 数据准备 List<Author> authors = getAuthors(); // 获取流并打印 authors.stream() .distinct() .filter(author -> author.getName().length() > 2) .forEach(author -> System.out.println(author.getName())); } }
map() 将流中的元素进行转换
public class StreamCenter { public static void main(String[] args) { // map() 将流中的元素进行转换 test2(); } /** * map() 将流中的元素进行转换 */ private static void test2() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .map(author -> author.getName()) .forEach(name -> System.out.println(name)); } }
map() 将流中元素进行计算
public class StreamCenter { public static void main(String[] args) { // map() 将流中元素进行计算 test3(); } /** * map() 将流中元素进行计算 */ private static void test3() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .map(author -> author.getAge()) .map(age -> age + 10) .forEach(System.out::println); } }
distinct() 去除重复元素
注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以注意重写equals方法;
public class StreamCenter { public static void main(String[] args) { // distinct() 去除重复元素 (distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以注意重写equals方法) test4(); } /** * distinct() 去除重复元素 (distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以注意重写equals方法) */ private static void test4() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .distinct() .forEach(author -> System.out.println(author.getName())); } }
sorted() 对流中的元素进行排序
注意:如果调用空参的sorted方法,需要流中的元素是实现了Comparable;
public class StreamCenter { public static void main(String[] args) { // sorted() 对流中的元素按年龄进行排序 (注意如果调用空参的sorted方法,需要流中的元素是实现了Comparable) test5(); } /** * sorted() 对流中的元素按年龄进行排序 */ private static void test5() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .sorted((o1, o2) -> o1.getAge() - o2.getAge()) .forEach(author -> System.out.println(author.getName() + "," + author.getAge())); } }
limit() 设置流的最大长度
注意:超出的部将被抛弃;
public class StreamCenter { public static void main(String[] args) { // limit() 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中两个年龄最大的作家 test6(); } /** * limit() 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中两个年龄最大的作家 */ private static void test6() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .distinct() .sorted((o1, o2) -> o2.getAge() - o1.getAge()) .limit(2) .forEach(author -> System.out.println(author.getName() + "," + author.getAge())); } }
skip() 跳过流中的几个元素
public class StreamCenter { public static void main(String[] args) { // skip() 跳过流中的几个元素 test7(); } // skip() 跳过流中的几个元素 private static void test7() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .skip(1) .forEach(author -> System.out.println(author.getName())); } }
flatMap() 将流中元素的多个对象作为流中的元素
public class StreamCenter { public static void main(String[] args) { // flatMap() 将流中元素的多个对象作为流中的元素 test8(); } /** * flatMap() 将流中元素的多个对象作为流中的元素 */ private static void test8() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .flatMap(author -> author.getBooks().stream()) .distinct() .forEach(book -> System.out.println(book.getName())); } }
打印现有数据的所有分类,要求去重,不能出现连着的分类:哲学,爱情
public class StreamCenter { public static void main(String[] args) { // 打印现有数据的所有分类,要求去重,不能出现连着的分类:哲学,爱情 test9(); } /** * 打印现有数据的所有分类,要求去重,不能出现连着的分类:哲学,爱情 */ private static void test9() { // 数据准备 List<Author> authors = getAuthors(); // 创建流并输出 authors.stream() .flatMap(author -> author.getBooks().stream()) .distinct() .flatMap(book -> Arrays.stream(book.getCategory().split(","))) .distinct() .forEach(category -> System.out.println(category)); } }
终结操作
forEach() 对流中的元素进行遍历操作
对流中的元素进行遍历操作,通过传入传入的参数去指定对遍历的元素进行什么具体操作;
private static void test01(List<Author> authors) { // 打印所有作家的名字,注意删除重复元素 authors.stream() // 将流中的元素进行转换,并返回 .map(author -> author.getName()) // 去重 .distinct() // 遍历流中的元素 .forEach(System.out::println); }
count() 获取当前流中元素的个数
private static void test02(List<Author> authors) { // 打印作家所出的书籍的数目,注意删除重复元素 long count = authors.stream() .flatMap(author -> author.getBooks().stream()) .distinct() .count(); // 输出 System.out.println(count); }
max()&min() 获取流中最大值-最小值
private static void test03(List<Author> authors) { // 获取这些作家分数最高和最低的书籍 Optional<Integer> max = authors.stream() .flatMap(author -> author.getBooks().stream()) .map(book -> book.getScore()) .max((score1, score2) -> score1 - score2); System.out.println("最大值:" + max.get()); Optional<Integer> min = authors.stream() .flatMap(author -> author.getBooks().stream()) .map(book -> book.getScore()) .min((score1, score2) -> score1 - score2); System.out.println("最小值:" + min.get()); }
collect() 把当前流转换成一个集合(重点)
List集合
private static void test04(List<Author> authors) { // 获取一个存放所有作者名字的List集合 List<String> nameList = authors.stream() .map(author -> author.getName()) .collect(Collectors.toList()); System.out.println(nameList); }
set集合
private static void test05(List<Author> authors) { // 获取一个所有书名的Set集合 Set<String> bookNameSet = authors.stream() .flatMap(author -> author.getBooks().stream()) .map(book -> book.getName()) .collect(Collectors.toSet()); System.out.println(bookNameSet); }
map集合
注意map集合的key值不能重复
private static void test06(List<Author> authors) { // 获取一个map集合,key是作者名,value是书名的list集合 Map<String, List<Book>> nameAndBookNameMap = authors.stream() .distinct() .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks())); }
anyMatch() 判断是否有任意符合匹配条件的元素,结果为boolean类型
anyMatch() 和filter()的区别:
filter():根据条件过滤流中的元素,符合条件的继续往下走
anyMatch():根据条件判断,是否有符合条件的元素,有则返回true,没有返回false
private static void test07(List<Author> authors) { // 判断是否有年龄在29以上的作家 boolean okAndNo = authors.stream() .anyMatch(author -> author.getAge() > 29); System.out.println(okAndNo); }
allMatch() 判断是否全部都符合条件,结果为boolean类型
private static void test08(List<Author> authors) { // 判断作家是否都是成年人 boolean okAndNo = authors.stream() .allMatch(author -> author.getAge() >= 18); System.out.println(okAndNo); }
noneMatch() 判断流中的元素是否都不符合匹配条件,如果都不符合结果为true,否则为false
private static void test09(List<Author> authors) { // 判断作家是否都没超过100岁 boolean okAndNo = authors.stream() .noneMatch(author -> author.getAge() > 100); System.out.println(okAndNo); }
findAny() 取出流中的任意一个元素
private static void test10(List<Author> authors) { // 获取任意一个年龄大于18的作家,如果存在就输出名字 Optional<Author> authorOptional = authors.stream() .filter(author -> author.getAge() > 18) .findAny(); authorOptional.ifPresent(author -> System.out.println(author.getName())); }
findFirst() 获取流中第一个元素
private static void test11(List<Author> authors) { // 获取一个年龄最小的作家,并输出他的名字 Optional<Author> minAge = authors.stream() .sorted((o1, o2) -> o1.getAge() - o2.getAge()) .findFirst(); minAge.ifPresent(author -> System.out.println(author.getName())); }
reduce() 对流中的数据按照你指定的计算方式计算出一个结果
reduce两个参数的重载形式内部的计算方式如下:
T result = identity; for (T element : this stream) { result = accumulator.apply(result,element) } return result;
求所有作家的年龄和
public class StreamEnd { public static void main(String[] args) { // reduce() 对流中的数据按照你指定的计算方式计算出一个结果 // 求所有作家的年龄和 // test12(authors); } /** * reduce() 对流中的数据按照你指定的计算方式计算出一个结果 * @param authors */ private static void test12(List<Author> authors) { // 求所有作家的年龄和 Integer avgSum = authors.stream() .map(author -> author.getAge()) .reduce(0, (result, element) -> result + element); System.out.println(avgSum); } }
求所有作家中年龄最大的值
public class StreamEnd { public static void main(String[] args) { // 求所有作家中年龄最大的值 test13(authors); } /** * reduce() 对流中的数据按照你指定的计算方式计算出一个结果 * @param authors */ private static void test13(List<Author> authors) { // 求所有作家中年龄最大的值 Integer ageMax = authors.stream() .map(author -> author.getAge()) .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result); System.out.println(ageMax); } }
求作家中年龄的最小值
public class StreamEnd { public static void main(String[] args) { // 求所有作家中年龄最大的值 test14(authors); } /** * reduce() 对流中的数据按照你指定的计算方式计算出一个结果 * @param authors */ private static void test14(List<Author> authors) { // 求作家中年龄的最小值 Integer ageMin = authors.stream() .map(author -> author.getAge()) .reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element); System.out.println(ageMin); } }
reduce一个参数的重载形式内部的计算
这个就相当于是把第一个元素值当成默认值来用(要注意,不要为为出现空值)
boolean foundAny = false; T result = null; for (T element : this stream) { if (!foundAny) { foundAny = true; result = element; } else { result = accumulator.apply(result,element); } } return foundAny ? Optional.of(result) : Optional.empty();
用一个参数的reduce求作家中年龄的最小值
public class StreamEnd { public static void main(String[] args) { // 用一个参数的reduce求作家中年龄的最小值 test15(authors); } /** * reduce() 对流中的数据按照你指定的计算方式计算出一个结果 * @param authors */ private static void test15(List<Author> authors) { // 用一个参数的reduce求作家中年龄的最小值 Optional<Integer> authorsOptional = authors.stream() .map(author -> author.getAge()) .reduce((result, element) -> result > element ? element : result); authorsOptional.ifPresent(age -> System.out.println(age)); } }
注意事项
1、惰性求值(如果没有终结操作,没有中间操作时不会得到执行的)
2、流是一次性的(一旦一个流对象经过一个终结操作后。这个流就不能再被使用)
3、不会影响原数据(我们在流中可以多数据做很多处理。但是正常情况下,不会影响原来集合中的元素的。这往往也是我们期待的)
以下是非正常操作(会影响原数据)
authors.stream() .map(author -> { author.setAge(author.getAge() + 10); return author; }) .forEach(list -> System.out.println(list)); System.out.println(authors);