先看一个小案例体验一下stream流有多方便
案例:创建一个集合,把集合所有以"张"开头的元素存储到一个新集合中,再把"张"开头的集合中的长度为3的元素存储到新的集合中,最后遍历得到的集合。
传统方式:
public class StreamDemo {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("张三丰");
list1.add("张益达");
list1.add("李逍遥");
list1.add("张良");
list1.add("小张");
ArrayList<String> list2 = new ArrayList<>();
for (String s : list1) {
if (s.startsWith("张")) {
list2.add(s);
}
}
ArrayList<String> list3 = new ArrayList<>();
for (String s : list2) {
if (s.length() == 3) {
list3.add(s);
}
}
for (String s : list3) {
System.out.println(s);
}
}
}
使用Stream流
list1.stream().filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
对比下来,使用Stream流写起来太简单啦!
Stream流的三类方法
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作。
中间方法
流水线上的操作。一次操作完毕后,还可以继续进行其他操作。
终结方法
一个Stream流只能有一个终结方法。
使用场景
单列集合
使用Collection接口中的默认方法stream()
//单列集合
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("sss");
list.add("vvv");
list.stream().forEach(s -> System.out.println(s));
控制台结果
双列集合
通过keySet或entrySet获取Set集合再获取Stream流
//双列集合
HashMap<String, Integer> hm = new HashMap<>();
hm.put("sdad", 20);
hm.put("hgkj", 23);
hm.put("wert", 26);
hm.put("dsgfsg", 29);
hm.keySet().stream().forEach(System.out::println);
hm.entrySet().stream().forEach(System.out::println);
控制台结果
数组
Arrays中的静态方法stream生成流
//数组
int[] arr = {1,2,3,4,5};
Arrays.stream(arr).forEach(System.out::println);
同种数据类型的多个数据
1,2,3,4,5...
"aaa" "bbb" "ccc"...
使用Stream.of(T...values)生成流
Stream.of(1,2,3,4,5).forEach(System.out::println);
中间操作方法filter
public class StreamDemo1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张益达");
list.add("李逍遥");
list.add("张良");
list.add("小张");
//filter方法获取流中的每一个数据
//test 方法中的s,依次表示流中的每一个数据
//我们只要在test方法中对s进行判断就可以了
//如果判断的结果为true,则当前的数据留下
//如果判断的结果为false,则当前数据就不要
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张");
}
});
//predicate接口中只有一个抽象方法test 所以我们可以使用lambda表达式来简化
list.stream().filter((String s) -> s.startsWith("张"));
}
}
其他中间操作方法
Stream <T> limit (long maxSize) : 截取指定参数个数的数据
Stream <T> skip (long n) : 跳过指定参数个数的数据
static <T> Stream<T> concat (Stream a, Stream b) : 合并a和b两个流为一个流
Stream <T> distinct () : 去除流中重复的元素。依赖hashcode和equals方法
public class StreamDemo1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张益达");
list.add("李逍遥");
list.add("张良");
list.add("张良");
list.add("小张");
list.add("小张");
list.add("小张");
// Stream <T> limit (long maxSize) : 截取指定参数个数的数据
list.stream().limit(2).forEach(s -> System.out.println(s));
// Stream <T> skip (long n) : 跳过指定参数个数的数据
list.stream().skip(2).forEach(s -> System.out.println(s));
// static <T> Stream<T> concat (Stream a, Stream b) : 合并a和b两个流为一个流
ArrayList<String> list2 = new ArrayList<>();
list2.add("萨达");
list2.add("春辉");
list2.add("饭馆");
Stream<String> stream2 = list2.stream();
Stream<String> stream1 = list.stream();
Stream.concat(stream1, stream2).forEach(s -> System.out.println(s));
// Stream <T> distinct () : 去除流中重复的元素。依赖hashcode和equals方法
list.stream().distinct().forEach(s -> System.out.println(s));
}
}
终结操作方法
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class StreamDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张益达");
list.add("李逍遥");
list.add("张良");
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// list.stream().forEach(System.out::println);
//long count():返回此流中的元素数
long count = list.stream().count();
System.out.println(count);
}
}
stream流的收集操作
import java.util.ArrayList;
import java.util.function.Predicate;
/**
* 定义一个集合,并添加一些指数1,2,3,4,5,6,7,8,9,10
* 将集合中的奇数删除,只保留偶数
* 遍历集合得到2,4,6,8,10
*/
public class StreamDemo3 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
// list.stream().filter(new Predicate<Integer>() {
// @Override
// public boolean test(Integer integer) {
// if(integer%2==0){
// return true;
// }
// return false;
// }
// });
// list.stream().filter((Integer integer)-> {
// if(integer%2==0){
// return true;
// }
// return false;
// }).forEach(System.out::println);
list.stream().filter((Integer integer)-> integer % 2 == 0).forEach(System.out::println);
}
}
遍历集合发现,集合并未发生变化。
结论:stream流中无法直接修改集合,数组等数据源中的数据
收集方法
.collect(Collectors.toList())
.collect(Collectors.toSet())
/**
* 定义一个集合,并添加一些指数1,2,3,4,5,6,7,8,9,10
* 将集合中的奇数删除,只保留偶数
* 遍历集合得到2,4,6,8,10
*/
public class StreamDemo4 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
list.add(10);
list.add(10);
List<Integer> list1 = list.stream().filter((Integer integer) -> integer % 2 == 0)
.collect(Collectors.toList());
System.out.println(list1);
Set<Integer> set = list.stream().filter((Integer integer) -> integer % 2 == 0).collect(Collectors.toSet());
System.out.println(set);
}
}
.collect(Collectors.toMap())
/**
* Stream流的收集方法
* 创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
* "zhangsan,23"
* "lisi,24"
* "wangwu,25"
* 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
*/
public class StreamDemo5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wangwu,25");
Map<String, Integer> map = list.stream().filter((String s) -> {
String[] split = s.split(",");
int age = Integer.parseInt(split[1]);
return age >= 24;
}).collect(Collectors.toMap(
(String s) -> {
return s.split(",")[0];
},
(String s) -> {
return Integer.parseInt(s.split(",")[1]);
}
));
//遍历map
for(Map.Entry<String,Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println((key + ":" + value));
}
}
}
练习
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
男演员只要名字为3个字的前三人
女演员只要姓林的,并且不要第一个
把过滤后的男演员姓名和女演员姓名合并到一起
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
/**
现在有两个ArrayList集合,
分别存储6名男演员名称和6名女演员名称,
要求完成如下的操作
- 男演员只要名字为3个字的前三人
- 女演员只要姓林的,并且不要第一个
- 把过滤后的男演员姓名和女演员姓名合并到一起
- 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
**/
public class ActorTest {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
list1.add("周润发");
list1.add("成龙");
list1.add("刘德华");
list1.add("吴京");
list1.add("周星驰");
list1.add("李连杰");
list2.add("邱淑贞");
list2.add("林小林");
list2.add("林青霞");
list2.add("柳岩");
list2.add("宋茜");
list2.add("王祖贤");
//男演员只要名字为3个字的前三人
List<String> manList = list1.stream().filter(s -> s.length()==3).limit(3).collect(Collectors.toList());
System.out.println(manList);
//女演员只要姓林的,并且不要第一个
List<String> womanList = list2.stream().filter(s -> s.startsWith("林")).skip(1).collect(Collectors.toList());
System.out.println(womanList);
//把过滤后的男演员姓名和女演员姓名合并到一起
Stream<String> stream = Stream.concat(manList.stream(), womanList.stream());
//把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
stream.forEach(name->{
Actor actor = new Actor(name);
System.out.println(actor);
});
}
}
最后,祝您身体健康,再见