java8Stream流的学习
StreamApi
流(Stream)是什么?
是数据渠道,用于操作数据源(集合 ,数组等)所生成的元素序列
集合讲的是数据,流讲的是计算
注意:
- Stream 自己不会存储元素
- Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream
- Stream 操作是延迟执行的,这意味着他们或会等到需要结果的时候才执行
Stream 操作的三歌步骤:
-
创建 Stream
- 一个数据源(集合、数组)获取流
-
中间操作
- 对数据流进行处理
-
终止操作
- 产生结果
1、创建Stream流的方式:
- 可用通过collection系列的集合提供的stream() 或parallelStream() 并行流
- 通过Arrays中的静态方法stream()
- 通过Stream中的静态方法of()
- 创建无限流
@Test
//创建流的方式
public void test1() {
//1、可用通过collection系列的集合提供的stream() 或parallelStream() 并行流
ArrayList<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//2、通过Arrays中的静态方法stream()
int[] ints = new int[10];
IntStream stream1 = Arrays.stream(ints);
//3、通过Stream中的静态方法of()
Stream<String> stream2 = Stream.of("aa", "bb", "c");
//4、创建无限流
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 1);
}
2、中间操作
中间操作不会执行任何的处理,只有遇到终止操作时,流才会一次性的全部处理。(惰性求值)
-
筛选与切片
- filter 接收lambda,从流中排除某些元素
- limit 截断流,使其元素不超过给定的数值
- skip(n) 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit互补
- distinct 通过流中元素的hashCode() 和equals() 去除重复元素
List<Employee> employees = Arrays.asList( new Employee("张三", 18, 3000), new Employee("李四", 18, 3000), new Employee("张三", 45, 8700), new Employee("王五", 26, 4500), new Employee("麻子", 30, 2700), new Employee("田七", 15, 200) ); @Test public void test2(){ employees.stream() //过滤拿到员工年龄超过20岁的 .filter((e) -> e.getAge() > 20) //Employee{name='张三', age=45, salary=8700.0} //Employee{name='王五', age=26, salary=4500.0} //Employee{name='麻子', age=30, salary=2700.0} //取出前两个元素 .limit(2) //Employee{name='张三', age=45, salary=8700.0} //Employee{name='王五', age=26, salary=4500.0} //跳过前一个元素 .skip(1) //Employee{name='王五', age=26, salary=4500.0} //去除重复(这里没有重复的) .distinct() //终止操作 .forEach(System.out::println); }
-
映射
- map 接收lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的流。
- flatMap 接收一个函数作为参数,将流中的每个值换成另一个流,然后把所有的流连接成一个流。
@Test public void test3(){ List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd"); list.stream() //把字符转大写 .map((s)-> s.toUpperCase(Locale.ROOT)) //AAA BBB CCC DDD .forEach(System.out::println); //获取数组中每个元素的字符 list.stream() .map(StreamApiTest::filterString) .forEach(sm -> sm.forEach(System.out::println)); // a a a b b b c c c d d d Stream<Stream<Character>> streamStream = list.stream() .map(StreamApiTest::filterString); streamStream.forEach((sm) -> sm.forEach(System.out::println)); // a a a b b b c c c d d d //用这个方法相当于上面的处理方法 list.stream() .flatMap(StreamApiTest::filterString) .forEach(System.out::println); // a a a b b b c c c d d d } //将字符串转化成字符流 public static Stream<Character> filterString(String str){ ArrayList<Character> list = new ArrayList<>(); for (char c : str.toCharArray()) { list.add(c); } return list.stream(); }
-
排序
- sorted() 自然排序( 按照comparable)比如String 中的comparaTo (实现了comparable接口的类)
- sorted( Comparator) 定制排序 (自己写的conparator排序)
@Test public void test4() { List<String> list = Arrays.asList("aaa", "ccc", "bbb", "ddd"); list.stream() //按照String中的实现了comparable的排序规则 .sorted() .forEach(System.out::println); // aaa bbb ccc ddd employees.stream() //按照自己写的排序规则来排序 .sorted((e1,e2)-> Integer.compare(e1.getAge(),e2.getAge())) .forEach(System.out::println); //Employee{name='田七', age=15, salary=200.0} //Employee{name='张三', age=18, salary=3000.0} //Employee{name='李四', age=18, salary=3000.0} //Employee{name='王五', age=26, salary=4500.0} //Employee{name='麻子', age=30, salary=2700.0} //Employee{name='张三', age=45, salary=8700.0} }
3、终止操作
-
查找与匹配
- allMatch 检查是否匹配所有元素
- anyMatch 检查 是否至少匹配一个元素
- noneMatch 检查是否没有匹配所有元素
- findFirst 返回第一个元素
- **findAny ** 返回当前流中任意元素
- count 返回流中的总个数
- max 返回流中最大值
- min 返回流中最小值
@Test public void test5(){ //判断是不是年龄都是18岁 boolean b = employees.stream() .allMatch((e) -> e.getAge().equals(18)); System.out.println(b); //false //判断是否有是18岁的 boolean b1 = employees.stream() .anyMatch((e) -> e.getAge().equals(18)); System.out.println(b1); //true //判断是不是没有20岁的 boolean b2 = employees.stream() .noneMatch((e) -> e.getAge().equals(20)); System.out.println(b2); //true //找出工资最低的那个 //Optional四个容器类,可以避免空指针异常 Optional<Employee> first = employees.stream() .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())) .findFirst(); System.out.println(first.get()); //Employee{name='田七', age=15, salary=200.0} //随便找一个年龄为18的 Optional<Employee> any = employees.stream() .filter((e) -> e.getAge().equals(18)) .findAny(); System.out.println(any.get()); //Employee{name='张三', age=18, salary=3000.0} //查看list中有多少个元素 long count = employees.stream() .count(); System.out.println(count); //6 //获取年龄最大的 Optional<Employee> max = employees.stream() .max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())); System.out.println(max.get()); //Employee{name='张三', age=45, salary=8700.0} //获取年龄最小的 Optional<Employee> min = employees.stream() .min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())); System.out.println(min.get()); //Employee{name='田七', age=15, salary=200.0} }
-
归约
- reduce(T identity, BinaryOperator) 可以将流中元素反复结合起来,得到一个值
@Test public void test6(){ List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); //对集合元素求和 Integer reduce = list.stream() .reduce(0, (x, y) -> x + y); System.out.println(reduce); //55 //求出工资总和 Optional<Double> salary = employees.stream() .map(Employee::getSalary) .reduce(Double::sum); System.out.println(salary.get()); //22100.0 }
**map和reduce的连接通常称为map-reduce模式,Google 用它来进行网络搜索而出名
-
收集
- collect 将流转换为其他形式,接收一个collector接口的实现,用于给Stream中元素汇总的方法
@Test public void test7(){ //将所有的名字放到一个集合中 List<String> list = employees.stream() .map(Employee::getName) .distinct() .collect(Collectors.toList()); System.out.println(list.toString()); //[张三, 李四, 王五, 麻子, 田七] //可以进行分组 (按年龄分组) Map<Integer, List<Employee>> collect = employees.stream() .collect(Collectors.groupingBy(Employee::getAge)); System.out.println(collect); //{18=[Employee{name='张三', age=18, salary=3000.0}, Employee{name='李四', age=18, salary=3000.0}], 26=[Employee{name='王五', age=26, salary=4500.0}], 45=[Employee{name='张三', age=45, salary=8700.0}], 30=[Employee{name='麻子', age=30, salary=2700.0}], 15=[Employee{name='田七', age=15, salary=200.0}]} }
collect功能强大,可以转换为很多的形式
成功没有捷径,一步一个脚印!