目录
2.1 Stream(流)是一个来自数据源的元素队列并支持聚合操作
3.1 通过Collection的Stream()(串行流)方法或者parallelstream()(并行流)方法创建Stream
3.3 通过Arrays中得静态方法stream()获取数组流
一、使用传统集合多步遍历与Stream流方式进行遍历
1.1使用传统方式遍历集合对集合进行过滤
public class DemoList {
public static void main(String[] args) {
// 创建list集合,存储姓名
List<String> list = new ArrayList<>();
list.add("lily");
list.add("linda");
list.add("bom");
// 对list集合中的元素进行过滤率,只要以l开头就存储到新的集合中
List<String> listA = new ArrayList<>();
for (String s : list) {
if(s.startsWith("l")) {
listA.add(s);
}
}
// 对listA集合进行过滤,姓名长度为4,存储到新集合中
List<String> listB = new ArrayList<>();
for (String s : listA) {
if(s.length() == 4) {
listB.add(s);
}
}
// 遍历listB集合
for (String s : listB) {
System.out.println(s);}
}}
这个练习用了三个循环。Stream的更优写法:
1.2 Stream进行优化
public class DemoList {
public static void main(String[] args) {
// 创建list集合,存储姓名
List<String> list = new ArrayList<>();
list.add("lily");
list.add("linda");
list.add("bom");
// 对list集合中的元素进行过滤率,只要以l开头就存储到新的集合中
// 对listA集合进行过滤,姓名长度为4,存储到新集合
// 便利listB集合
list.stream().filter(name -> name.startsWith("l"))
.filter(name -> name.length() == 4)
.forEach(name -> System.out.println(name));
}}
filter中传的参数是Predicate(j进行判断)所以可以传递lambda
forEach中传的参数是Consumer(消费一个数据),同样也可以传递lambda
二、什么是Stream
2.1 Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(lambda)(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
2.2特点
Stream流属于管道流,只能被消费(使用)一次
第一个Stream流调用完毕方法,数据就会转到下一个Stream上
而这时Stream流已经使用完毕,就会关闭了
所以第一个Stream流就不在调用方法了
// 创建一个Stream流
Stream<String> stream = Stream.of("lily","linda","bom");
// 对流中的元素进行过滤,只要l
Stream<String> stream2 = stream.filter(name -> name.startsWith("l"));
// 对stream2进行遍历
stream2.forEach(name -> System.out.println(name));
再次使用stream流进行遍历
stream.forEach(name -> System.out.println(name));
运行后:
stream has already been operated upon or closed
三、生成流
3.1 通过Collection的Stream()(串行流)方法或者parallelstream()(并行流)方法创建Stream
default stream<E> stream()
//把集合转换成Stream流
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Stream<String> stream1 = list.parallelStream();
对map进行操作
Map<String, String> map = new HashMap<String, String>();
//。获取键,存储到一个set集和
Set<String> keyset = map.keySet();
Stream<String> stream = keyset.stream();
//。获取值,存储到一个collection集合中
Collection<String> values = map.values();
Stream<String> stream2 = values.stream();
//。获取键值对,键与值是映射关系,entrySet
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<String> stream3 = entries.stream();
3.2 stream接口的静态方法0f可以获取数组对应的流
static <T> Stream <T> of (T ... values)
//将数组转换为Stream流
Stream<Integer> stream = Stream.of(1,2,3,4,5);
// 可变参数可以传递数组
Integer[] arr = {1,2,3,4,5};
Stream<Integer> stream2 = Stream.of(arr);
3.3 通过Arrays中得静态方法stream()获取数组流
IntStream stream = Arrays.stream(new int[] {1,2,3});
3.4 创建无限流(迭代、生成)
//迭代,需要传入一个起始值,然后传入一个一元操作
Stream<Integer> stream = Stream.iterate(2, (x) -> x * 2);
// 生成无限产生对象
Stream<Double> stream2 = Stream.generate(() -> Math.random());
四、Stream流中常用方法
4.1Stream流中API方法分为两类
(1)终结方法(及早求值):返回值类型不再是Stream接口自身类型的方法,因此不再支持链式调用
及早求值得到的是最终结果而不是stream。
count 和 forEach,max,min
(2)延迟方法(惰性求值):返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用,除了终结方法为其与方法均为延迟方法。
filter,map,flatMap
4.2 forEach
与for循环中的for-each不同
* void forEach(Consumer<? super T> action)
* 该方法接收一个Consumer接口函数,会将每一个流元素交给函数进行处理
* Consumer接口是一个消费型的函数式接口,可以传递lambda,其中有一个方法accept(s)进行消费数据
//获取Stream流
Stream<String> stream = Stream.of("aa","cc","ads");
// 使用Stream中的方法forEach对Stream中的数据进行遍历
stream.forEach(name -> System.out.println(name));
4.3 过滤 filter
用于对Stream中的数据进行过滤得到新的子集
// 创建一个Stream流
Stream<String> stream = Stream.of("lily","linda","bom");
// 对流中的元素进行过滤,只要l
Stream<String> stream2 = stream.filter(name -> name.startsWith("l"));
// 对stream2进行遍历
stream2.forEach(name -> System.out.println(name));
4.4 映射 map
* <R> Stream<R> map(Function<? super T, ? extends R> mapper)
* Function函数式接口中的R apply(T t).根据类型T的参数获取类型R的结果
* 这种可以将一种T类型转换成R类型的转换动作,称之为映射
Stream<String> stream = Stream.of("1","2","3");
// 使用map把String转换成Integer
Stream<Integer> stream2 = stream.map(s -> Integer.parseInt(s));
// 遍历stream2
stream2.forEach(i -> System.out.println(i));
4.5 统计个数: count
用于统计Stream流种元素的个数
是个终结方法
返回值是个long类型的整数
不能再继续调用Stream流中的其他方法
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
long count = list.stream().count();
System.out.println(count);
4.6 取用前几个: limit
可以对流进行截取
是一个延迟方法
只是对流中的元素进行截取
返回的是新的流
可以继续调用Stream流中的方法
* Stream<T> limit(long maxSize)
* 参数是一个long型,如果集合当前长度大于参数增进行截取
String[] arr = {"as","asd","sdf"};
Stream<String> stream = Stream.of(arr);
Stream<String> stream2 = stream.limit(2);
stream2.forEach(name -> System.out.println(name));
运行结果:
4.7跳过前几个: skip
如果希望跳过恰鸡各元素,可以使用skip获取一个截取之后的新流
* Stream<T> skip(long n)
如果当前溜达的长度为大于n,则跳过前n个,否则会得到一个长度为0的空流
String[] arr = {"as","asd","sdf"};
Stream<String> stream = Stream.of(arr);
Stream<String> stream2 = stream.skip(1);
stream2.forEach(name -> System.out.println(name));
运行结果:
4.8 组合 concat
将两个流合并成一个流
String[] arr = {"as","asd","sdf"};
Stream<String> stream = Stream.of(arr);
Stream<String> stream1 = Stream.of("lily","linda","bom");
Stream.concat(stream, stream1).forEach(name -> System.out.println(name));
4.9 并行(parallel)程序
List<String> list = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = list.parallelStream().filter(s -> s.isEmpty()).count();
System.out.println(count);
4.10 Collectors
Collectors类实现了很多归约操作,例如将流转换成集合和聚合元素。
// collectors用于返回列表
List<String> s = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = s.stream().filter(String -> !String.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表" + filtered);
// collectors用于返回字符串
String mergedString = s.stream().filter(String -> !String.isEmpty()).collect(Collectors.joining(","));
System.out.println("筛选列表" + mergedString);
4.11 统计
一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
五、练习
* 第一个list中筛选名字四三个长度,筛选后要前两个
* 第二个list中筛选名字为l,要后两个
* 根据姓名创建Person对象,存储到一个新集合中
* 打印整个Person对象信息
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("lily");
list1.add("linda");
list1.add("bom");
list1.add("aila");
list1.add("comy");
// 第一个list中筛选名字四个长度,筛选后要前两个
Stream<String> first = list1.stream().filter(name -> name.length() == 4).limit(2);
List<String> list2 = new ArrayList<>();
list2.add("lily");
list2.add("linda");
list2.add("bom");
list2.add("lambda");
list2.add("comy");
Stream<String> second = list2.stream().filter(name -> name.startsWith("l")).skip(2);
// 根据姓名创建Person对象,存储到一个新集合中
// 打印整个Person对象信息
// 通过map映射成Person
Stream.concat(first, second).map(name -> new Person(name)).forEach(p -> System.out.println(p));
运行结果: