概念
流是从支持数据处理操作的源生成的元素序列
流水线操作,内部迭代
中间操作
操作 | 返回类型 | 操作参数 | 函数描述符 |
---|---|---|---|
filter | Stream | Predicate | T -> boolean |
distinct | Stream | long | |
skip | Stream | ||
limit | Stream | ||
map | Stream | Function | T -> R |
flatMap | Stream | Function> | T -> Stream |
sorted | Stream | Comparator | (T,T) -> int |
终端操作
操作 | 返回类型 | 操作参数 | 函数描述符 |
---|---|---|---|
anyMatch | boolean | Predicate | T -> boolean |
allMatch | boolean | Predicate | T -> boolean |
noneMatch | boolean | Predicate | T -> boolean |
findFirst | Optional | ||
findAny | Optional | ||
reduce | Optional | BinaryOperator | (T,T) -> T |
forEach | void | Consumer | T -> void |
collect | R | Collector | |
count | long |
流操作
构建流
//值创建流
Stream<String> stream = Stream.of("Hello","World");
stream.map(String::toUpperCase).forEach(System.out::println);
//数组创建流
int[] numbers = {1,2,3,4,5};
int sum = Arrays.stream(numbers).sum();
//文件生成流
try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
.distinct()
.count();
}
//函数生成无限流
Stream.generate(Math::radom).limit(10).forEach(System.out::println);
谓词 筛选
Lish<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)//谓词筛选
.collect(toList());
去重 筛选
List<Integer> numbers = Arrays.asList(1,2,3,4,5,2);
numbers.stream()
.filter(i -> i%2 == 0)
.distinct()//去重
.forEach(System.out::print);
截短 筛选
List<Dish> dishes = menu.stream()
.filter(d -> d.getCalories > 300)
.limit(3)//截断
.collect(toList());
跳过 筛选
Lish<Dish> dishes = menu.stream()
.filter(d -> d.getCalories() > 300)
.skip(2)//跳过
.collect(toList());
map 映射
List<String> dishName = menu.stream()
.map(Dish::getName)//映射
.collect(toList());
flatMap 映射
List<String> uniqueCharacters = words.stream()
.map(w -> w.split("")) //单词变为字母数组
.flatMap(Arrays::stream) //各个流转化为单个流
.distinct()
.collect(Collectors.toList());
匹配
//至少匹配(终端操作)
if(menu.stream().anyMatch(Dish::isVegetarian)){
System.out.println("菜单中有素食");
}
//全部匹配
boolean isHealthy = menu.stream().allMatch(d -> d.getCalories < 1000 );
boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories >= 1000 );
查找
List<Integet> someNumbers = Arrays.asList(1,2,3,4,5);
Optional<Integer> firstOne = someNumbers.stream()
.map(x -> x*x )
.filter( x -> x%3 ==0)
.findFirst(); // findAny多用于并行流
求和 归约
int sum = numbers.stream().reduce(0, (a,b) -> a+b );
最值 归约
Optional<Integer> max = numbers.stream().reduce(Integer::max);
收集器
//总数
long dishesNumber = menu.stream().collect(Collectiors.counting());
//最值
Optional<Dish> mostCalorieDish = menu.stream().collect(maxBy(dishCaloriesComparator));
//汇总
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
//平均数
double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));
//拼接字符串
String shortmenu = menu.stream().map(Dish::getName).collect(joining());
String shortmenu = menu.stream().collect(joining());
//分组
Map<Dish.Type,List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType));
//分组各数量
Map<Dish.Type, Long> typesCount = menu.stream().collect(groupingBy(Dish::getType, counting()));
//分区
Map<Boolean, List<Dish>> partitionedMenu = menu.stream().collect(partitioningBy(Dish::isVegetarian));
并行流
stream.parallel().filter(...).sequential().map(...).parallel().reduce;
- 自动装箱和拆箱会降低性能,尽量用原始类型流,如IntStream、LongStream
- 有些操作并行流操作性能低,特别是依赖于顺序操作,如:findFirst
- 数据量小的数据不值得用并行流
- 考虑流背后的数据结构是否易于分解
源 | 可分解性 |
---|---|
ArrayList | 极佳 |
IntStream.range | 极佳 |
HashSet | 好 |
TreeSet | 好 |
LinkedList | 差 |
Stream.iterate | 差 |
小结
流通过中间操作和终端操作对数据进行操作,使得数据操作如同操作SQL一样;
另外,并行流在提高性能的同时,也要考虑一些因素来高效的使用它