Stream流
传统方式
/*
操作要求:
1. 首先筛选所有姓张的人;
2. 然后筛选名字有三个字的人;
3. 最后进行对结果进行打印输出。
*/
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//1. 首先筛选所有姓张的人;
//定义集合,保存本次筛选后的结果
List<String> zhangList = new ArrayList<>();
//遍历集合,拿到每一个元素,判断是否以张开头
for (String str : list) {
if(str.startsWith("张")) {
zhangList.add(str);
}
}
// 2. 然后筛选名字有三个字的人;
//定义集合,保存本次筛选后的结果
List<String> threeList = new ArrayList<>();
//遍历上次筛选后的结果,拿到里面的每一个元素,判断是否是三个字
for (String str : zhangList) {
if(str.length() == 3) {
threeList.add(str);
}
}
//3. 最后进行对结果进行打印输出。
for (String str : threeList) {
System.out.println(str);
}
System.out.println("=================================");
//Stream流初体验
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
}
结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/68fd2040a90544ce9128e173edca8a37.png)
-
获取流的三种方式
Stream<T>是一个接口,该接口表示流。 1.通过Collection集合获取流: 在Collection中有一个方法叫做stream,这个方法可以通过单列集合获取流 Collection中获取流的方法: Stream<E> stream():获取单列集合对应的流。 2.Map集合不能直接获取流,有三种间接获取流的方式(了解) a. 先获取Map集合中所有的键,通过所有的键获取流。 b. 先获取Map集合中所有的值,通过所有的值获取流 c. 先获取Map集合中所有的键值对(Entry)对象,通过所有的键值对对象获取流 3. 数组获取流的方式 在Stream中有一个静态方法叫做of,可以通过数组获取流。 static Stream of(T... values):获取流
单列集合获取流:
/*
获取流的两种方式
1. 通过Collection集合(单列集合)调用stream()方法获取。【根据单列集合获取】
2. 通过Stream中的静态方法根据数组获取流。【根据数组获取】
*/
public class Demo02CollectionGetStream {
public static void main(String[] args) {
//创建集合
List<String> list = new ArrayList<>();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
//获取集合对应的流
Stream<String> stream = list.stream();
//通过流调用toArray将流转成数组,然后通过Arrays工具类将数组中的内容转成字符串,然后通过外面的输出语句输出。
System.out.println(Arrays.toString(stream.toArray()));
}
}
数组获取流:
/*
在Stream中有一个静态方法,可以根据数组获取流。
*/
public class Demo03ArrayGetStream {
public static void main(String[] args) {
//创建数组
String[] strArr = {"hello", "world", "java"};
//通过Stream调用of方法,根据数组获取流
//Stream<String> stream = Stream.of(strArr);
//of方法不仅可以根据数组获取流,也可以根据多个元素获取流
Stream<String> stream = Stream.of("你好", "我好", "大家好");
//输出流中的内容
System.out.println(Arrays.toString(stream.toArray()));
}
}
-
Stream中常见方法
forEach:逐一处理 filter:过滤筛选 count:获取个数 limit:获取前几个 skip:跳过前几个 map:映射(映射其实指的就是将原来流中的每一个元素都进行某种操作,然后将操作后的元素保存到新的流中。) concat:合并
forEach:逐一处理:
/*
在Stream中有一个方法叫做forEach,可以对流中的元素进行逐一处理,逐一操作
void forEach(Consumer action):对流中的每一个元素进行逐一操作,逐一处理。参数Consumer表示处理规则。
Consumer是一个函数式接口,这个接口中只有一个抽象方法
void accept(T t):对数据进行操作,进行处理。
forEach方法的参数是Consumer函数式接口,那么可以传递Lambda表达式,这个Lambda表达式表示的是Consumer接口中唯一的一个抽象方法
accept的内容,我们要在Lambda表达式中编写操作规则。
*/
public class Demo04ForEach {
public static void main(String[] args) {
//获取Stream流
Stream<String> stream = Stream.of("hello", "world", "java");
//调用forEach方法,对流中的每一个元素进行逐一处理(输出)
//Lambda表达式中的参数s表示流中的每一个元素。
stream.forEach(s -> System.out.println(s));
}
}
filter:过滤筛选:
/*
在Stream中有一个方法叫做filter,可以对流中的元素进行过滤筛选。
Stream<T> filter(Predicate predicate):用来对流中的元素进行过滤筛选,返回值是过滤后新的流。参数predicate表示过滤规则。
Predicate是一个函数式接口,里面只有一个抽象方法
boolean test(T t):判断数据是否符合要求。
filter方法参数是Predicate函数式接口,所以可以传递Lambda表达式,该Lambda表达式表示Predicate接口中的唯一的抽象方法
test的内容。我们要在Lambda表达式中编写验证(判断)规则。 如果我们希望某个数据留下,那么就返回true,如果不希望某个数据
留下,那么就返回false。
*/
public class Demo05Filter {
public static void main(String[] args) {
//获取Stream流
Stream<String> stream = Stream.of("aa", "bbbbbb", "cc", "ddddd");
//对流中的元素进行过滤,只留下长度小于3的元素。
//参数s表示流中的每一个元素,Lambda表达式的方法体是过滤的规则,如果结果是true,元素留下
Stream<String> newStream = stream.filter(s -> s.length() < 3);
//对过滤后新的流中的元素进行逐一处理,逐一输出
newStream.forEach(s -> System.out.println(s));
}
}
count:获取个数:
/*
在Stream中有一个方法叫做count,可以获取流中元素的个数。
long count():获取流中的元素的个数。
*/
public class Demo06Count {
public static void main(String[] args) {
//获取流对象
Stream<String> stream = Stream.of("aa", "bb", "cc", "dd");
//long count():获取流中的元素的个数。
long c = stream.count();
System.out.println(c);
}
}
limit:获取前几个:
/*
在Stream中有一个方法叫做limit,可以获取流中的前几个元素。
Stream<T> limit(long n):获取流中的前n个元素然后放入到新的流中返回。
*/
public class Demo07Limit {
public static void main(String[] args) {
//获取Stream流
Stream<String> stream = Stream.of("aa", "bb", "cc", "dd", "ee");
//获取流中的前3个元素
Stream<String> newStream = stream.limit(3);
//逐一处理
newStream.forEach(s -> System.out.println(s));
}
}
skip:跳过前几个:
/*
在Stream中有一个方法叫做skip,可以跳过流中的前几个元素,获取剩下的元素
Stream<T> skip(long n):跳过流中前n个元素,获取剩下的元素放到一个新的流中返回。
*/
public class Demo08Skip {
public static void main(String[] args) {
//获取Stream流
Stream<String> stream = Stream.of("aa", "bb", "cc", "dd", "ee");
//调用skip方法,跳过流中的前3个元素,获取剩下的
Stream<String> newStream = stream.skip(3);
//输出newStream中的元素
newStream.forEach(s -> System.out.println(s));
}
}
map:映射:
/*
在Stream中有一个方法就叫做map,可以将流中的元素【映射】到另一个流中。
举例:
原来的流:"10", "20", "30"
映射后新的流:10, 20, 30
映射其实指的就是将原来流中的每一个元素都进行某种操作,然后将操作后的元素保存到新的流中。
Stream中的map方法:
Stream map(Function mapper):将流中的元素映射到新的流中并返回。参数Function表示映射规则。
Function是一个函数式接口,里面只有一个抽象方法叫做apply
R apply(T t):对数据进行处理,然后返回结果。
map方法的参数是Function这个函数式接口,那么我们可以传递Lambda表达式, 这个Lambda表达式表示的Function中唯一的一个抽象方法
map方法的内容,我们在Lambda表达式中编写处理的规则。
*/
public class Demo10Map {
public static void main(String[] args) {
//获取Stream流
Stream<String> stream = Stream.of("10", "20", "30");
//将原来流中的每一个元素变成数字保存到新的流中(将原来流中的元素变成数字映射到新的流)
//Lambda表达式中的参数s表示原来流中的每一个元素,然后将流中的每一个元素变成了数字保存在新的流中。
Stream<Integer> newStream = stream.map(s -> Integer.parseInt(s));
//输出结果
newStream.forEach(s -> System.out.println(s));
}
}
concat:合并:
/*
在Stream中有一个静态方法叫做concat,可以对两个流进行合并,合并成新的流。
static Stream concat(Stream a, Stream b):对a和b这两个流进行合并,合并成新的流返回。
*/
public class Demo09Concat {
public static void main(String[] args) {
//获取两个流
Stream<String> streamOne = Stream.of("aa", "bb");
Stream<String> streamTwo = Stream.of("cc", "dd");
//对两个流合并,合并成新的流
Stream<String> stream = Stream.concat(streamOne, streamTwo);
//逐一处理
stream.forEach(s -> System.out.println(s));
}
}
Stream中的注意事项:
/*
Stream中的注意事项:
1. 流调用非终结方法返回值都是Stream本身类型,但是返回的并不是自身的对象,返回的结果是一个新的流
2. 流只能一次性使用,不能多次使用。
*/
public class Demo11Stream {
public static void main(String[] args) {
//获取流
Stream<String> stream = Stream.of("aa", "bb", "cc");
//调用非终结方法
Stream<String> newStream = stream.limit(2);
//比较两个流对象的地址值
//System.out.println(stream == newStream);
//流只能一次性使用,不能多次使用。
//stream.skip(1);
}
}
练习:
传统方式:
public class Person {
private String name;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/*
现在有两个ArrayList 集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)
依次进行以下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 根据姓名创建Person 对象;
7. 打印整个队伍的Person对象信息。
*/
public class Demo01PrintList {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
one.add("欧阳锋");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
//1. 第一个队伍只要名字为3个字的成员姓名;
List<String> oneA = new ArrayList<>();
//遍历one,拿到每一个元素判断名字是否是三个字,如果是,就添加到oneA中
for (String s : one) {
if (s.length() == 3) {
oneA.add(s);
}
}
//2. 第一个队伍筛选之后只要前3个人;
List<String> oneB = new ArrayList<>();
//遍历oneA,只获取前三个元素添加到oneB
for (int i = 0; i < 3; i++) {//0 1 2
//获取元素
String str = oneA.get(i);
//添加到oneB中
oneB.add(str);
}
//3. 第二个队伍只要姓张的成员姓名;
List<String> twoA = new ArrayList<>();
//遍历two,拿到里面的每一个元素,判断是否姓张,如果姓张,就添加到twoA集合
for (String str : two) {
if (str.startsWith("张")) {
twoA.add(str);
}
}
//4. 第二个队伍筛选之后不要前2个人;
List<String> twoB = new ArrayList<>();
//遍历twoA,跳过前两个元素,拿到后面的每一个元素添加到twoB
for (int i = 2; i < twoA.size(); i++) {
String str = twoA.get(i);
twoB.add(str);
}
//5. 将两个队伍合并为一个队伍;
List<String> totalList = new ArrayList<>();
totalList.addAll(oneB);//将oneB中的所有的元素添加到totalList中。
totalList.addAll(twoB);//将twoB中的所有的元素添加到totalList中
//6. 根据姓名创建Person 对象;
//将totalList中的每一个字符串姓名变成Person对象保存【映射】到新的集合
List<Person> personList = new ArrayList<>();
//遍历totalList集合,拿到每一个姓名,根据姓名创建Person对象,添加到personList集合
for (String name : totalList) {
personList.add(new Person(name));
}
//7. 遍历打印整个队伍的Person对象信息。
for (Person person : personList) {
System.out.println(person);
}
}
}
Stream流的方式:
/*
现在有两个ArrayList 集合存储队伍当中的多个成员姓名,要求使用Stream流操作集合
依次进行以下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 根据姓名创建Person 对象;
7. 打印整个队伍的Person对象信息。
*/
public class Demo02PrintList {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
one.add("欧阳锋");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
//1. 第一个队伍只要名字为3个字的成员姓名;
//2. 第一个队伍筛选之后只要前3个人;
Stream<String> streamOne = one.stream().filter(s -> s.length() == 3).limit(3);
//3. 第二个队伍只要姓张的成员姓名;
//4. 第二个队伍筛选之后不要前2个人;
Stream<String> streamTwo = two.stream().filter(s -> s.startsWith("张")).skip(2);
//5. 将两个队伍合并为一个队伍;
//6. 根据姓名创建Person 对象;
//7. 打印整个队伍的Person对象信息。
Stream.concat(streamOne, streamTwo).map(s -> new Person(s)).forEach(p -> System.out.println(p));
}
}
- Stream流收集元素
收集到集合中
stream.collect(Collectors.toList):收集到List集合
stream.collect(Collectors.toSet):收集到Set集合
将Stream流中的元素收集到数组
stream.toArray();
收集到List/Set集合:
/*
将流中的元素收集到集合中(将流转成集合)
在Stream中有一个方法叫做collect,可以将流中的元素收集到集合(将流转成集合)
R collect(Collector collector):参数collector表示将数据收集到哪种集合。
Collector是一个接口,我们要使用这个接口的实现类对象,这个接口的实现类对象不是由我们去创建的,而是通过
工具类获取,获取Collector的工具类叫做Collectors
Collectors中获取Collector的方法:
static Collector toList():通过该方法获取到的Collector对象表示将数据收集到List集合。
static Collector toSet():通过该方法获取到的Collector对象表示将数据收集到Set集合。
*/
public class Demo01StreamToList {
public static void main(String[] args) {
//获取Stream流
Stream<String> stream = Stream.of("hello", "world", "java", "php");
//将流中的元素收集到List集合(将流转成List集合)
//List<String> list = stream.collect(Collectors.toList());
//System.out.println(list);
//将流中的元素收集到Set集合(将流转成Set集合)
Set<String> set = stream.collect(Collectors.toSet());
System.out.println(set);
}
}
收集到数组:
/*
在Stream中有一个方法叫做toArray,可以将流中的内容收集到数组中(将流转成数组)
Object[] toArray():将流转成数组
*/
public class Demo02StreamToArray {
public static void main(String[] args) {
//获取流
Stream<String> stream = Stream.of("hello", "world", "java", "php");
//将流转成数组
Object[] objArr = stream.toArray();
//遍历打印
for (Object o : objArr) {
System.out.println(o);
}
}
}
流式思想: