一、简介
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
二、什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
元素:是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
数据源 :流的来源。可以是集合,数组,I/O channel,产生器generator等。
聚合操作: 类似SQL语句一样的操作,比如filter, map, reduce, find,match, sorted等。
和以前的Collection操作不同,Stream操作还有两个基础的特征:
Pipelining::中间操作都会返回流对象本身。这样多个操作可以串联成一个管道,如同流式风格(fluent style)。这样做可以对操作进行优化,比如延迟执行(laziness)和短路( short-circuiting)。
/**
* Stream(流)是一个来自数据源的元素队列并支持聚合操作
*
* 元素:是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
*
* 数据源 :流的来源。可以是集合,数组,I/O channel,产生器generator等。
*
* 聚合操作: 类似SQL语句一样的操作,比如filter, map, reduce, find,match, sorted等。
*
* 和以前的Collection操作不同,Stream操作还有两个基础的特征:
*
* Pipelining::中间操作都会返回流对象本身。这样多个操作可以串联成一个管道,如同流式风格(fluent style)。
*
* 这样做可以对操作进行优化,比如延迟执行(laziness)和短路( short-circuiting)。
* ---------------------
*/
public class StreamTestor {
public static void main(String[] args) throws Exception {
List<Task> tasks = Arrays.asList(
new Task(Status.CLOSED,12),
new Task(Status.OPEN,34),
new Task(Status.CLOSED,45)
);
/** 1、生成流
* stream() −为集合创建串行流。
* parallelStream() − 为集合创建并行流。
*/
List<String> strings = Arrays.asList("abc","","efg","kij");
List<String> filtered = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
System.out.println(filtered.toString());
System.out.println("-------------------------------------------");
/**
* 2、forEach
* Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用forEach 输出了10个随机数
*/
Random random = new Random();
random.ints(5,10).limit(10).forEach(System.out::println);
System.out.println("-------------------------------------------");
/** 3、map
* map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
*/
List<Integer> numbers = Arrays.asList(1,2,3,2,3,4,5);
// 去对应的平方数
/**
* 1、numbers 集合被转换成stream流表示
* 2、map 将流中数元素映射到新的结果集合
* 3、distinct 对新集合进行去重
* 4、Collectors toList()规约操作,将流转换成集合
*/
List<Integer> subLists = numbers.stream().map(i -> i*i).distinct().collect(Collectors.toList());
subLists.forEach(m-> System.out.println(m));
System.out.println("-------------------------------------------");
/**
* 4、filter
* filter 方法用于通过设置条件过滤出元素。以下代码片段使用filter 方法过滤出空字符串:
*/
List<String> strs = Arrays.asList("ad","sc","","dc","");
// 获取空字符串
long count = strs.stream().filter(s->!s.isEmpty()).count();
System.out.println(count);
System.out.println("-------------------------------------------");
/** 5.limit
* limit 方法用于获取指定数量的流。以下代码片段使用 limit 方法打印出 10 条数据:
*/
List<String> res = strs.stream().filter(s->!s.isEmpty()).limit(1).collect(Collectors.toList());
res.forEach(System.out::println);
System.out.println("-------------------------------------------");
/** 6、sorted
* sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
*
*/
Random random1 = new Random();
random1.ints(1,100).limit(10).sorted().forEach(System.out::println);
System.out.println("-------------------------------------------");
/**
* 7、parallerStream
* parallelStream 是流并行处理程序的代替方法。以下实例我们使用parallelStream 来输出空字符串的数量:
*/
List<String> strs2 = Arrays.asList("ad","sc","","dc","");
long count1 = strs2.parallelStream().filter(s->s.isEmpty()).count();
System.out.println(count1);
System.out.println("-------------------------------------------");
/** 8、collectors
* Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors可用于返回列表或字符串
*/
List<String> stringList = Arrays.asList("a","b","","c","d");
List<String> filter = stringList.stream().filter(s->!s.isEmpty()).collect(Collectors.toList());
// "筛选列表: "
filter.forEach(System.out::println);
String mergeStr = stringList.stream().filter(s->!s.isEmpty()).collect(Collectors.joining(","));
System.out.println("合并字符串:"+mergeStr);
System.out.println("-------------------------------------------");
/** 9、统计
* 另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
*/
List<Integer> numbers2 = Arrays.asList(1,3,46,7,6,7,4,8,9);
IntSummaryStatistics stat = numbers2.stream().mapToInt(x->x).summaryStatistics();
System.out.println("最大值:"+stat.getMax());
System.out.println("最小值:"+stat.getMin());
System.out.println("平均值:"+stat.getAverage());
System.out.println("求和:"+stat.getSum());
System.out.println("-------------------------------------------");
/**
* 10、groupby
* 规约操作中,根据某个条件进行分组
*/
Map<Status,List<Task> > map = tasks.stream().collect(Collectors.groupingBy(s->s.status));
System.out.println(map);
System.out.println("-------------------------------------------");
/**
* 11、求各个元素分数在集合中的占比
*/
double totalPoint = tasks.parallelStream().mapToDouble(s->s.points).sum();
List<String> result = tasks.stream().map(s->s.points/totalPoint).mapToDouble(w->(long)(w*100)).boxed()
.map(percentage->percentage+"%").collect(Collectors.toList());
result.forEach(System.out::println);
System.out.println("-------------------------------------------");
/**
* 文件读取
* Stream的方法onClose 返回一个等价的有额外句柄的Stream,当Stream的close()方法被调用的时候这个句柄会被执行
*/
final Path path = new File( "README.md" ).toPath();
Stream< String > lines = Files.lines(path, StandardCharsets.UTF_8 );
//lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
lines.forEach(System.out::println);
}
private enum Status {
OPEN, CLOSED
};
private static final class Task {
private final Status status;
private final Integer points;
Task( final Status status, final Integer points ) {
this.status = status;
this.points = points;
}
public Integer getPoints() {
return points;
}
public Status getStatus() {
return status;
}
@Override
public String toString() {
return String.format( "[%s, %d]", status, points );
}
}
}