一、案例引入
案例需求:
- 创建一个集合,存储多个姓名字符串元素;
- 把集合中所有以“张”开头的元素存储到一个新的集合;
- 把上述集合中长度为3的元素存储到一个新的集合;
- 遍历后打印上一步得到的集合
传统方法:
public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//把集合中所有以"张"开头的元素存储到一个新的集合
ArrayList<String> zhangList = new ArrayList<String>();
for(String s : list) {
if(s.startsWith("张")) {
zhangList.add(s);
}
}
// System.out.println(zhangList);
//把"张"开头的集合中的长度为3的元素存储到一个新的集合
ArrayList<String> threeList = new ArrayList<String>();
for(String s : zhangList) {
if(s.length() == 3) {
threeList.add(s);
}
}
// System.out.println(threeList);
//遍历上一步得到的集合
for(String s : threeList) {
System.out.println(s);
}
}
}
Stream改进后:
public class StreamDemo {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//Stream流来改进
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
}
}
二、Stream流概述
(一)Stream流思想
(二)Stream流的三类方法
1、获取Stream流
创建一条流水线,把数据放到流水线上准备对其进行操作
2、中间方法
流水线上对数据进行操作,一次操作完后还可以继续对其进行操作
3、终结方法
一系列中间方法操作完成后的最后一个操作,一个Stream流只能有一个终结方法
三、Stream流的生成
1、Collection体系集合
使用默认方法stream()生成流:default Stream<E> stream()
2、Map体系集合
把Map转成Set集合,间接生成流
3、数组
通过Arrays中的静态方法stream生成流
4、同种数据类型的多个数据
通过Stream接口的静态方法of(T…values)
示例:
public class StreamDemo {
public static void main(String[] args) {
//Collection体系的集合可以使用默认方法stream()生成流
List<String> list = new ArrayList<String>();
Stream<String> listStream = list.stream();
Set<String> set = new HashSet<String>();
Stream<String> setStream = set.stream();
//Map体系的集合间接的生成流
Map<String,Integer> map = new HashMap<String, Integer>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
//数组可以通过Arrays中的静态方法stream生成流
String[] strArray = {"hello","world","java"};
Stream<String> strArrayStream = Arrays.stream(strArray);
//同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
Stream<Integer> intStream = Stream.of(10, 20, 30);
}
}
四、Stream流中间操作方法
中间操作代表执行该操作后依然可以继续执行其他操作。
常见方法
方法名 | 说明 |
Stream<T> filter(Predicate predicate) | 用于对流中的数据进行过滤 |
Stream<T> limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream<T> skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream<T> distinct() | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
filter示例:
//需求1:把list集合中以张开头的元素在控制台输出
list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
//需求2:把list集合中长度为3的元素在控制台输出
list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
//需求3:把list集合中以张开头的,长度为3的元素在控制台输出
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
limit&skip示例:
//需求1:取前3个数据在控制台输出
list.stream().limit(3).forEach(System.out::println);
System.out.println("--------");
//需求2:跳过3个元素,把剩下的元素在控制台输出
list.stream().skip(3).forEach(System.out::println);
System.out.println("--------");
//需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
list.stream().skip(2).limit(2).forEach(System.out::println);
concat&distinct示例:
//需求1:取前4个数据组成一个流
Stream<String> s1 = list.stream().limit(4);
//需求2:跳过2个数据组成一个流
Stream<String> s2 = list.stream().skip(2);
//需求3:合并需求1和需求2得到的流,并把结果在控制台输出
Stream.concat(s1,s2).forEach(System.out::println);
//需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
Stream.concat(s1,s2).distinct().forEach(System.out::println);
五、Stream流终结操作方法
执行完此方法之后,Stream流将不能再执行其他操作。
常见方法
方法名 | 说明 |
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
示例:
//需求1:把集合中的元素在控制台输出
list.stream().forEach(System.out::println);
//需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出
long count = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(count);
六、Stream流的收集操作
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。
1、常用方法
方法名 | 说明 |
R collect(Collector collector) | 把结果收集到集合中 |
2、工具类Collectors提供的具体收集方法
方法名 | 说明 |
public static <T> Collector toList() | 把元素收集到List集合中 |
public static <T> Collector toSet() | 把元素收集到Set集合中 |
public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
Collector toList示例:
//需求1:得到名字为3个字的流
Stream<String> listStream = list.stream().filter(s -> s.length() == 3);
//需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历
List<String> names = listStream.collect(Collectors.toList());
for(String name : names) {
System.out.println(name);
}
Collector toSet示例:
//需求3:得到年龄大于25的流
Stream<Integer> setStream = set.stream().filter(age -> age > 25);
//需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历
Set<Integer> ages = setStream.collect(Collectors.toSet());
for(Integer age : ages) {
System.out.println(age);
}
Collector toMap示例:
//需求5:得到字符串中年龄数据大于28的流
Stream<String> arrayStream = Stream.of(strArray).filter(s ->
Integer.parseInt(s.split(",")[1]) > 28);
//需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值
Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")
[0], s -> Integer.parseInt(s.split(",")[1])));
Set<String> keySet = map.keySet();
for (String key : keySet) {
Integer value = map.get(key);
System.out.println(key + "," + value);
}
七、总结
1、Stream基于函数式编程思想,使用 Stream 流可以让开发者以一种更简洁、更易读的方式表达数据处理的逻辑,对一个整数集合进行过滤、映射和求和操作;传统的方式可能需要使用多个循环和中间变量,而使用 Stream 流可以在一条语句中完成。
2、中间操作会返回一个新的 Stream 流,允许进行链式操作。
3、Stream 流可以很方便地实现并行处理,以充分利用多核处理器的优势,提高程序的执行效率。
4、传统的集合遍历通常使用for循环或者迭代器,而 Stream 流提供了更简洁的forEach
方法来遍历集合。
5、通过map
、flatMap
等操作可以方便地对集合中的元素进行转换。通过reduce
、collect
等操作可以实现数据的聚合。例如使用collect
方法将流中的元素收集到一个新的集合中。