可以看成遍历数据集的高级迭代器。
和迭代器类似,流只能遍历一次。
代码:
package com.hw;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
public class Main1 {
public static void main(String[] args) {
List<Apple> lists = Arrays.asList(new Apple[]{
new Apple(10), new Apple(20), new Apple(30)
});
// 过滤
List<Apple> t1 = new ArrayList<>();
for (Apple a : lists) {
if (a.getWeight() > 10) {
t1.add(a);
}
}
List<Apple> t2 = lists.stream().filter(a -> a.getWeight() > 10).collect(toList());
// 排序
Collections.sort(lists, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight().compareTo(o2.getWeight());
}
});
Stream<Apple> s1 = lists.stream().sorted(Comparator.comparing(Apple::getName));
// 按名称分组
Map<String, List<Apple>> m1 = lists.stream().sorted().collect(groupingBy(Apple::getName));
List<Dish> menu = Arrays.asList(
new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 300, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH) );
// 外部迭代
for (Dish h : menu) { // 语法糖
System.out.println(h.getCalories());
}
// 内部迭代
Iterator<Dish> iterator = menu.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next().getCalories());
}
// 终止操作
// count, forEach, collect, anyMatch, allMatch, noneMatch, findAny, findFirst, reduct
long si = menu.stream().count(); // count
menu.stream().forEach(System.out::println); // forEach
List<String> l1 = menu.stream().map(Dish::getName).collect(toList()); // collect
// 中间操作
// filter, map , flatMap, limit , skip, sorted, distinct,
List<String> l11 = menu.stream().filter(Dish::isVegetarian)
.distinct().limit(10).skip(2)
.map(Dish::getName).collect(toList());
String s = menu.stream().map(Dish::getName).collect(Collectors.joining()); // joining
IntStream sa = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> sb = sa.boxed();
int i1 = menu.stream().mapToInt(Dish::getCalories).sum();
OptionalInt oa = menu.stream().mapToInt(Dish::getCalories).max();
int maxx = oa.orElse(1);
// 数值范围
// 生成偶数
IntStream ibb = IntStream.rangeClosed(1, 100).filter(i -> i%2 == 0);
System.out.println(ibb.count()); // 50
// 生成勾股数对
Stream<int[]> sss = IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100).filter(b -> Math.sqrt(a*a+b*b)%1 == 0)
.mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a*a+b*b)}));
List<Integer> l22 = menu.stream().filter(Dish::isVegetarian)
.distinct().limit(10).skip(2)
.map(Dish::getName)
.map(String::length)
.collect(toList());
// 流的扁平化
String[] arrayOfWords = {"Goodbye", "World"};
Stream<String> words = Arrays.stream(arrayOfWords);
// map
List<Stream<String>> a11 = words.map(w -> w.split(""))
.map(Arrays::stream)
.distinct().collect(toList());
// flatmap
// flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流
List<String> ll = words.map(w -> w.split(""))
.flatMap(Arrays::stream)
.distinct().collect(toList());
// 返回两个列表的数对
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> parirs = numbers1.stream()
.flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
.collect(toList());
// 返回只能被3整除的数对
List<int[]> parirs1 = numbers1.stream()
.flatMap(i -> numbers2.stream()
.filter(j -> (i+j)%3 == 0)
.map(j -> new int[]{i, j}))
.collect(toList());
// 查找和匹配
// 短路特性
if (menu.stream().anyMatch(Dish::isVegetarian)) {
// 有素菜可以选择
}
boolean b1 = menu.stream().allMatch(a -> a.getCalories() > 10);
boolean b2 = menu.stream().noneMatch(a -> a.getCalories() > 1000);
// 匹配
// 短路
menu.stream().filter(a -> a.getCalories() > 10).findAny()
.ifPresent(d -> System.out.println(d.getCalories()));
// 查找第一个元素
Optional<Dish> o11 = menu.stream().filter(a -> a.getCalories() > 10).findFirst();
// 归约
// 将流归约成一个值
// 求和
int sum = menu.stream().map(Dish::getCalories).collect(toList())
.stream().reduce(0, (a, b) -> a + b);
int sum1 = menu.stream().map(Dish::getCalories).collect(toList())
.stream().reduce(0, Integer::sum);
/**
* reduce接受两个参数:
* 一个初始值,这里是0;
* 一个BinaryOperator<T>来将两个元素结合起来产生一个新值,
*/
// 无初始值
// reduce还有一个重载的变体,它不接受初始值,但是会返回一个Optional对象:
Optional<Integer> o1 = menu.stream().map(Dish::getCalories).collect(toList())
.stream().reduce(Integer::sum);
// 求最值
Optional<Integer> max1 = menu.stream().map(Dish::getCalories).collect(toList())
.stream().reduce(Integer::max);
Optional<Integer> min1 = menu.stream().map(Dish::getCalories).collect(toList())
.stream().reduce(Integer::min);
// 由值创建流
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
Stream<String> emptyStream = Stream.empty();
// 由数组创建流
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum11 = Arrays.stream(numbers).sum();
// 由文件生成流
/**
* Java中用于处理文件等I/O操作的NIO API(非阻塞 I/O)已更新,以便利用Stream API。
* java.nio.file.Files中的很多静态方法都会返回一个流
*/
long nu = 0;
try (Stream<String> lines = Files.lines(Paths.get("t.txt"), Charset.defaultCharset())) {
nu = lines.flatMap(line -> Arrays.stream(line.split(" "))).distinct().count();
} catch (IOException e) {}
// 由函数生成流:创建无限流
// Stream API提供了两个静态方法来从函数生成流: Stream.iterate和Stream.generate
// 迭代
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
// 用iterate方法生成斐波纳契元组序列中的前20个元素
Stream.iterate(new int[]{0, 1},
t -> new int[]{t[1], t[0]+t[1]})
.limit(20)
.forEach(t -> System.out.println("(" + t[0] + "," + t[1] +")"));
Stream.iterate(new int[]{0, 1},
t -> new int[]{t[1],t[0] + t[1]})
.limit(10)
.map(t -> t[0])
.forEach(System.out::println);
// 生成
/**
* 与iterate方法类似, generate方法也可让你按需生成一个无限流。但generate不是依次
* 对每个新生成的值应用函数的。它接受一个Supplier<T>类型的Lambda提供新的值
*/
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
}
}
Map<String, Integer> carInventory = new HashMap<>();
Integer count = 0;
if(map.containsKey("Aston Martin")){
count = map.get("Aston Martin");
}
Integer count = map.getOrDefault("Aston Martin", 0);
public String getData(String url){
String data = cache.get(url);
if(data == null){
data = getData(url);
cache.put(url, data);
}
return data;
}
public String getData(String url){
return cache.computeIfAbsent(url, this::getData);
}
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.replaceAll(x -> x * 2);
System.out.println(numbers);
removeIf方法可以移除集合中满足某个谓词的所有元素。
String authors = String.join(", ", "Raoul", "Mario", "Alan");
System.out.println(authors);
总结:
可以更高效地处理集合。
流可以简洁地表达复杂的数据处理查询。
流可以透明地并行化。
可以使用filter、 distinct、 skip和limit对流做筛选和切片。
可以使用map和flatMap提取或转换流中的元素。
可 以 使 用 findFirst 和 findAny 方 法 查 找 流 中 的 元 素 。
可 以 用 allMatch 、noneMatch和anyMatch方法让流匹配给定的谓词。
这些方法都利用了短路:找到结果就立即停止计算;没有必要处理整个流。
可以利用reduce方法将流中所有的元素迭代合并成一个结果,例如求和或查找最大元素。
filter和map等操作是无状态的,它们并不存储任何状态。
reduce等操作要存储状态才能计算出一个值。
sorted和distinct等操作也要存储状态,因为它们需要把流中的所有元素缓存起来才能返回一个新的流。
这种操作称为有状态操作。
流有三种基本的原始类型特化: IntStream、 DoubleStream和LongStream。
它们的操作也有相应的特化。
流不仅可以从集合创建,也可从值、数组、文件以及iterate与generate等特定方法创建。
无限流是没有固定大小的流。
网友评论