一.Sream流概述
我们可以把集合|数组,转换为Stream流,使用Stream流中的方法,对集合|数组进行操作
作用:简化代码,使我们的代码更加优雅
2.Stream流的基本体验
需求:
List list= new ArrayList<>();
Collections.addAll(list,“张无忌”,“周芷若”,“赵敏”,“张三丰”,“张翠山”,“灭绝师太”,“张三”);
1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中
2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中
3.对最后得到的集合进行遍历
package com.itheima.demo05Stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Stream流的基本体验
需求:
List<String> list= new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中
2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中
3.对最后得到的集合进行遍历
*/
public class Demo01List {
public static void main(String[] args) {
List<String> list= new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
//1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中
List<String> zhangList= new ArrayList<>();
for (String s : list) {
if(s.startsWith("张")){
zhangList.add(s);
}
}
System.out.println(zhangList);//[张无忌, 张三丰, 张翠山, 张三]
//2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中
List<String> sanList= new ArrayList<>();
for (String s : zhangList) {
if(s.length()==3){
sanList.add(s);
}
}
//3.对最后得到的集合进行遍历
for (String s : sanList) {
System.out.println(s);
}
}
}
package com.itheima.demo05Stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Stream流:我们可以把集合|数组,转换为Stream流,使用Stream流中的方法,对集合|数组进行操作
作用:简化代码,使我们的代码更加优雅
*/
public class Demo02Stream {
public static void main(String[] args) {
List<String> list= new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
//1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中
//2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中
//3.对最后得到的集合进行遍历
list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(s-> System.out.println(s));
}
}
三.流式思想概述
四.获取Stream流的方式(重点)
package com.itheima.demo05Stream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.stream.Stream;
/*
5.3 获取流的方式
1.在JDK1.8版本之后Collection接口,里边定义了一个方法叫stream,用于把集合转换为Stream流
default Stream<E> stream() 返回一个序列 Stream与此集合作为其来源。
Collection接口下所有的实现类都可以使用stream方法
2.在JDK1.8版本之后,定义Stream接口,在接口定义了一个方法叫of,可以把可变参数(数组)转换为Stream流
java.util.stream.Stream<T>接口
static <T> Stream<T> of(T... values) 方法参数传递可变参数,也可以传递数组
*/
public class Demo03Stream {
public static void main(String[] args) {
show02();
}
/*
把可变参数(数组)转换为Stream流
*/
private static void show02() {
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
Stream<String> stream2 = Stream.of("aaa", "bbb", "ccc", "ddd");
//可变参数底层就是一个数组,可以传递可变参数的方法,都可以传递数组
String[] arr1 = {"aaa", "bbb", "ccc", "ddd"};
Stream<String> stream3 = Stream.of(arr1);
int[] arr2 = {1,2,3,4,5,6};
//把int[]作为一个元素存储到Stream流中
Stream<int[]> stream4 = Stream.of(arr2);
System.out.println(stream4.count());//1
//数组的类型不能使用基本类型,只能使用包装类
Integer[] arr3 = {1,2,3,4,5,6};
Stream<Integer> stream5 = Stream.of(arr3);
System.out.println(stream5.count());//6
}
/*
把Collection接口下的集合转换为Stream流
*/
private static void show01() {
ArrayList<String> list = new ArrayList<>();
//把ArrayList集合转换为Stream流
Stream<String> stream1 = list.stream();
LinkedList<Integer> linked = new LinkedList<>();
//把LinkedList集合转换为Stream流
Stream<Integer> stream2 = linked.stream();
HashSet<String> set = new HashSet<>();
//把HashSet集合转换为Stream流
Stream<String> stream3 = set.stream();
HashMap<String,String> map = new HashMap<>();
//map.stream();//Cannot resolve method 'stream()' Map集合不能转换为Stream流
}
}
五.Stream的常用方法(重点)
流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
- 终结方法:方法的返回值类型不再是
Stream
接口自身类型的方法,因此不再支持类似StringBuilder
那样的链式调用。本小节中,终结方法包括count
和forEach
方法。 - 非终结方法:返回值类型仍然是
Stream
接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为非终结方法。)
函数拼接与终结方法
在上述介绍的各种方法中,凡是返回值仍然为Stream
接口的为函数拼接方法,它们支持链式调用;而返回值不再为Stream
接口的为终结方法,不再支持链式调用。如下表所示:
备注:本小节之外的更多方法,请自行参考API文档。
1).forEach方法:用于遍历
package com.itheima.demo06StreamMethod;
import java.util.function.Consumer;
import java.util.stream.Stream;
/*
Stream流中的常用方法_forEach:用于遍历Stream流中的元素
void forEach(Consumer<? super T> action) 对此流的每个元素执行操作。
参数:
Consumer<? super T> action:是一个消费型的接口,参数可以传递Lambda表达式
唯一的抽象方法:
void accept(T t) :消费一个指定泛型类型的数据
注意:
forEach方法是一个终结方法,没有返回值;也不能使用链式编程调用Stream流中的其他方法了
*/
public class Demo01forEach {
public static void main(String[] args) {
//获取Stream流对象
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
//使用forEach方法遍历Stream流:依次打印Stream流中的元素
/*stream.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
System.out.println(i);
}
});*/
//Consumer是一个函数式接口,所以可以使用Lambda表达式简化接口的匿名内部类
/*
IllegalStateException: stream has already been operated upon or closed
非法状态异常:Stream流对象只能使用一次,使用完毕就会转换到下一个Stream流对象
之前的Stream流对象就会关闭了
*/
/*stream.forEach((Integer i)->{
System.out.println(i);
});*/
//Stream流的简化格式
//stream.forEach(i-> System.out.println(i));
stream.forEach(s-> System.out.println(s));
}
}
2).count方法:统计个数
package com.itheima.demo06StreamMethod;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/*
Stream流中的常用方法_count方法:统计个数
long count() 返回此流中的元素数。
注意:
count方法是一个终结方法,返回值类型是long类型;也不能使用链式编程调用Stream流中的其他方法了
*/
public class Demo02count {
public static void main(String[] args) {
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
long c1 = stream1.count();
System.out.println("c1:"+c1);//c1:6
List<String> list= new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
//把List集合转换为Stream流
Stream<String> stream2 = list.stream();
long c2 = stream2.count();
System.out.println("c2:"+c2);//c2:7
}
}
3).filter方法:过滤
package com.itheima.demo06StreamMethod;
import java.util.function.Predicate;
import java.util.stream.Stream;
/*
Stream流中的常用方法_filter方法:用于过滤Stream流中的元素
Stream<T> filter(Predicate<? super T> predicate)
参数:
Predicate<? super T> predicate:函数式接口,参数传递lambda表达式
唯一的抽象方法:
boolean test(T t) 用于对接口指定泛型类型的数据进行判断
注意:
filter方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo03filter {
public static void main(String[] args) {
Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "灰太狼", "红太狼", "小灰灰");
//使用Stream流中的方法filter过滤Stream流,只要包含"羊羊"元素,存储到一个新的Stream流中
/*Stream<String> stream2 = stream.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("羊羊");
}
});*/
//Predicate是一个函数式接口,所以可以使用Lambda表达式简化匿名内部类
/*Stream<String> stream2 = stream.filter((String s)->{
return s.contains("羊羊");
});*/
//简化Lambda表达式
//Stream<String> stream2 = stream.filter(s->s.contains("羊羊"));
//遍历Stream2流对象
//stream2.forEach(s-> System.out.println(s));
//链式编程
stream.filter(s -> s.contains("羊羊")).forEach(s -> System.out.println(s));
}
}
4).limit方法:获取前n个元素
package com.itheima.demo06StreamMethod;
import java.util.stream.Stream;
/*
Stream流中的常用方法_limit方法:获取前n个元素
Stream<T> limit(long maxSize) 返回由此流的元素组成的流,截短长度不能超过 maxSize 。
例如:
limit(4);获取流中的前4个元素,把4个元素存储到一个新的Steam流中
注意:
1.传递数字大于流的长度,返回流中所有的元素
2.limit方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo04limit {
public static void main(String[] args) {
Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊", "慢羊羊",
"暖羊羊", "灰太狼", "红太狼", "小灰灰");
//使用limit方法获取Stream流中前6个元素,存储到一个新的Stream流中返回
//Stream<String> stream2 = stream.limit(6);
//遍历stream2流对象
//stream2.forEach(s -> System.out.println(s));
//链式编程
stream.limit(6).forEach(s -> System.out.println(s));
}
}
5).skip:跳过前n个元素
package com.itheima.demo06StreamMethod;
import java.util.stream.Stream;
/*
Stream流中的常用方法_skip方法:跳过前n个元素
Stream<T> skip(long n)
skip(3)==> 跳过前3个元素,把剩余的元素存储到一个新的Stream流中
注意:
1.skip跳过的元素数量大于流中的个数,返回一个没有元素的空流
2.skip方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo05skip {
public static void main(String[] args) {
Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊", "慢羊羊",
"暖羊羊", "灰太狼", "红太狼", "小灰灰");
//使用skip方法跳过前6个元素,把剩余的元素存储到一个新的流中
//Stream<String> stream2 = stream.skip(6);
//遍历stream2流对象
//stream2.forEach(s -> System.out.println(s));
//链式编程
stream.skip(6).forEach(s -> System.out.println(s));
}
}
6).map方法:映射,类型转换
package com.itheima.demo06StreamMethod;
import java.util.function.Function;
import java.util.stream.Stream;
/*
Stream流中的常用方法_map方法:映射,类型转换
<R> Stream<R> map(Function<T,R> mapper)
参数:
Function<T,R> mapper:函数式接口,可以传递Lambda表达式
接口中唯一的抽象方法:
R apply(T t) 根据参数类型T获取类型R类型的返回值,用于类型转换 T转换R
注意:
map方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo06map {
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30");
//需求:使用map方法,把String类型的Stream流转换为Integer类型的Stream流
/*Stream<Integer> stream2 = stream.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
});*/
//Function接口是一个函数式接口,可以使用Lambda表达式简化匿名内部类
/*Stream<Integer> stream2 = stream.map((String s) -> {
return Integer.parseInt(s);
});*/
//简化lambda表达式
//Stream<Integer> stream2 = stream.map(s -> Integer.parseInt(s));
//遍历stream2流对象
//stream2.forEach(s-> System.out.println(s+100));
//链式编程
stream.map(s -> Integer.parseInt(s)).forEach(s-> System.out.println(s));
Stream<String> stream3 = Stream.of("张三", "李四", "王五");
//需求:使用map方法,把String类型的Stream流转换为Person类型的Stream流
//Stream<Person> stream4 = stream3.map(s -> new Person(s));
//遍历stream4流对象
//stream4.forEach(p-> System.out.println(p));
//链式编程
stream3.map(s -> new Person(s)).forEach(p-> System.out.println(p));
}
}
package com.itheima.demo06StreamMethod;
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
7).concat方法:组合
package com.itheima.demo06StreamMethod;
import java.util.stream.Stream;
/*
Stream流中的常用方法_concat方法:组合,把两个Stream流,组合为一个新的Stream流
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
注意:
concat方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo07concat {
public static void main(String[] args) {
Stream<String> stream1 = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊",
"慢羊羊", "暖羊羊", "灰太狼", "红太狼", "小灰灰");
Stream<String> stream2 = Stream.of("张三", "李四", "王五");
//使用Stream接口中的静态方法concat,把两个流对象合成一个新的流对象
//Stream<String> stream = Stream.concat(stream1, stream2);
//stream.forEach(s -> System.out.println(s));
//链式编程
Stream.concat(stream1,stream2).forEach(s -> System.out.println(s));
}
}
六.收集Stream结果(重点)
把Stream流转换为集合或者把Stream流转换为数组
1).把Stream流转换为集合:收集到集合中
package com.itheima.demo08Stream;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
把Stream流转换为集合:收集到集合中
可以使用Stream流中的方法collect把Stream转换为集合
R collect(Collector<? super T,A,R> collector)
参数:
Collector是一个接口,需要传递接口的实现类对象
java.util.stream.Collectors:操作Collector的工具类
static <T> Collector<T,?,List<T>> toList() 返回Collector接口的实现类对象,可以把Stream流转换为List集合
static <T> Collector<T,?,Set<T>> toSet() 返回Collector接口的实现类对象,可以把Stream流转换为Set集合
*/
public class Demo01StreamToCollection {
public static void main(String[] args) {
Stream<String> stream = Stream.of("美羊羊", "喜羊羊",
"懒羊羊", "沸羊羊", "慢羊羊", "暖羊羊","美羊羊");
//把Stream流转换为List集合:1.有序 2.可重复 3.有带索引的方法
//List<String> list = stream.collect(Collectors.toList());
//System.out.println(list);//[美羊羊, 喜羊羊, 懒羊羊, 沸羊羊, 慢羊羊, 暖羊羊, 美羊羊]
//把Stream流转换为Set集合:1.不允许重复 2.不包含代索引的方法
Set<String> set = stream.collect(Collectors.toSet());
System.out.println(set);//[美羊羊, 沸羊羊, 暖羊羊, 喜羊羊, 懒羊羊, 慢羊羊]
}
}
2).把Stream流转换为数组:收集到数组中
package com.itheima.demo08Stream;
import java.util.Arrays;
import java.util.stream.Stream;
/*
将流中的元素收集到数组(将流转成数组)
Stream接口中的方法
Object[] toArray() 把Stream流转换为数组
*/
public class Demo02StreamToArray {
public static void main(String[] args) {
Stream<String> stream = Stream.of("美羊羊", "喜羊羊",
"懒羊羊", "沸羊羊", "慢羊羊", "暖羊羊","美羊羊");
Object[] arr = stream.toArray();
System.out.println(Arrays.toString(arr));
}
}