概念:
使用流,无需迭代集合中的元素,就可以从管道提取和操作元素。这些管道通常被组合在一起,形成一系列对流进行操作的管道。
在大多数情况下,将对象存储在集合中是为了处理他们,因此你将会发现你将把编程的主要焦点从集合转移到了流上。
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);