概念:
使用流,无需迭代集合中的元素,就可以从管道提取和操作元素。这些管道通常被组合在一起,形成一系列对流进行操作的管道。
在大多数情况下,将对象存储在集合中是为了处理他们,因此你将会发现你将把编程的主要焦点从集合转移到了流上。
Java 8 采用的解决方案是:在接口中添加被 default
(默认
)修饰的方法。通过这种方案,设计者们可以将流式(stream)方法平滑地嵌入到现有类中。流方法预置的操作几乎已满足了我们平常所有的需求。流操作的类型有三种:创建流,修改流元素(中间操作, Intermediate Operations),消费流元素(终端操作, Terminal Operations)。最后一种类型通常意味着收集流元素(通常是到集合中)。
流创建
使用StreamOf可以轻松将数组转换成流。
void forEach(Consumer<? super T> action);这个是Stream类中的一个方法,参数是函数式接口,我们传一个实现实现类的方法即可。
@FunctionalInterface
public interface Consumer<T> {
// streams/StreamOf.java
import java.util.stream.*;
public class StreamOf {
public static void main(String[] args) {
Stream.of(new Bubble(1), new Bubble(2), new Bubble(3))
.forEach(System.out::println);
Stream.of("It's ", "a ", "wonderful ", "day ", "for ", "pie!")
.forEach(System.out::print);
System.out.println();
Stream.of(3.14159, 2.718, 1.618)
.forEach(System.out::println);
}
}
使用stream()可以轻松将集合转换成流
map方法可以作为元素过滤器使用
public class CollectionToStream {
public static void main(String[] args) {
/* List<Bubble> bubbles = Arrays.asList(new Bubble(1), new Bubble(2), new Bubble(3));
System.out.println(bubbles.stream()
.mapToInt(b -> b.i)
.sum());*/
Set<String> w = new HashSet<>(Arrays.asList("It's a wonderful day for pie!".split(" ")));
w.stream()
.map(x -> x + " ")
.forEach(System.out::print);
System.out.println();
Map<String, Double> m = new HashMap<>();
m.put("pi", 3.14159);
m.put("e", 2.718);
m.put("phi", 1.618);
m.entrySet().stream()
.map(e -> e.getKey() + ": " + e.getValue())
.forEach(System.out::println);
}
}
随机数产生
boxed()方法会将基本类型的数据包装成为对应的装箱类型,进而能被泛型方法show()调用。
public class RandomGenerators {
public static <T> void show(Stream<T> stream) {
stream
.limit(4)
.forEach(System.out::println);
System.out.println("++++++++");
}
public static void main(String[] args) {
Random rand = new Random(47);
show(rand.ints().boxed());
show(rand.longs().boxed());
show(rand.doubles().boxed());
// 控制上限和下限:
show(rand.ints(10, 20).boxed());
show(rand.longs(50, 100).boxed());
show(rand.doubles(20, 30).boxed());
// 控制流大小:
show(rand.ints(2).boxed());
show(rand.longs(2).boxed());
show(rand.doubles(2).boxed());
// 控制流的大小和界限
show(rand.ints(3, 3, 9).boxed());
show(rand.longs(3, 12, 22).boxed());
show(rand.doubles(3, 11.5, 12.3).boxed());
}
}
Random 为任意对象集合创建 Supplier
当你用 Collectors.joining()
作为 collect()
的参数时,将得到一个String
类型的结果,该结果是流中的所有元素被joining()
的参数隔开。
public class RandomWords implements Supplier<String> {
List<String> words = new ArrayList<>();
Random rand = new Random(47);
RandomWords(String fname) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(fname));
// 略过第一行
for (String line : lines.subList(1, lines.size())) {
for (String word : line.split("[ .?,]+"))
words.add(word.toLowerCase());
}
}
public String get() {
return words.get(rand.nextInt(words.size()));
}
/* @Override
public String toString() {
return words.stream()
.collect(Collectors.joining(" "));
}*/
public static void main(String[] args) throws Exception {
System.out.println(
Stream.generate(new RandomWords("D:\\myGitHub\\Java\\SingaporeJava\\project\\versionjdk18\\stream\\src\\Cheese.dat"))
.limit(10)
.collect(Collectors.joining(" ")));
}
}
流的建造者模式
在建造者模式(Builder design pattern)中,首先创建一个 builder
对象,然后将创建流所需的多个信息传递给它,最后builder
对象执行”创建“流的操作。Stream 库提供了这样的 Builder
。在这里,我们重新审视文件读取并将其转换成为单词流的过程。
public class FileToWordsBuilder {
Stream.Builder<String> builder = Stream.builder();
public FileToWordsBuilder(String filePath) throws Exception {
Files.lines(Paths.get(filePath))
.skip(1) // 略过开头的注释行
.forEach(line -> {
for (String w : line.split("[ .?,]+"))
builder.add(w);
});
}
Stream<String> stream() {
return builder.build();
}
public static void main(String[] args) throws Exception {
new FileToWordsBuilder("Cheese.dat")
.stream()
.limit(7)
.map(w -> w + " ")
.forEach(System.out::print);
}
}
Arrays
Arrays
类中含有一个名为 stream()
的静态方法用于把数组转换成为流。
public class ArrayStreams {
public static void main(String[] args) {
Arrays.stream(new double[] { 3.14159, 2.718, 1.618 })
.forEach(n -> System.out.format("%f ", n));
System.out.println();
Arrays.stream(new int[] { 1, 3, 5 })
.forEach(n -> System.out.format("%d ", n));
System.out.println();
Arrays.stream(new long[] { 11, 22, 44, 66 })
.forEach(n -> System.out.format("%d ", n));
System.out.println();
// 选择一个子域:
Arrays.stream(new int[] { 1, 3, 5, 7, 15, 28, 37 }, 3, 6)
.forEach(n -> System.out.format("%d ", n));
}
}
使用正则表达式分割字符串生成流
public class FileToWordsRegexp {
private String all;
public FileToWordsRegexp(String filePath) throws Exception {
all = Files.lines(Paths.get(filePath))
.skip(1) // First (comment) line
.collect(Collectors.joining(" "));
}
public Stream<String> stream() {
return Pattern
.compile("[ .,?]+").splitAsStream(all);
}
public static void
main(String[] args) throws Exception {
FileToWordsRegexp fw = new FileToWordsRegexp("Cheese.dat");
fw.stream()
.limit(7)
.map(w -> w + " ")
.forEach(System.out::print);
fw.stream()
.skip(7)
.limit(2)
.map(w -> w + " ")
.forEach(System.out::print);
}
}
String str = "wo ai,ni?zhong.guo";
Pattern.compile("[ .,?]+").splitAsStream(str).map(w -> w + " ").forEach(System.out::print);