filter、map和flatMap方法
filter
filter通过转换产生过滤后的新流,将字符串流转化为只包含长单词的另一个流。
List words = ...;
Stream longWords = words.stream().filter(w->w.length()>12)
filter类型是Predicate(谓词,表示动作)类型对象,从一个T映射到boolean值的函数。
map
map可以用来按照某种方式来转换流中的值。
将所有单词转换为小写:
Stream lowercaseWords = words.stream().map(String::toLowerCase);
通常使用lamdba表达式替代,新流包含所有单词首字母:
Stream firstLetters = words.stream().map(s->s.substring(0,1));
flatMap
摊平流
codePoints方式是字符串的编码点。
codePoints("Hello")返回的流是由"H","e","l","l","o"构成。
codePoints收集多个结果,最自然的方式是返回一个Stream对象。
Stream> result = words.stream().map(w -> codePoints(w));
得到:[..["y","o","u","r"],["b","o","a","t"],...]
将其摊平[...,"y","o","u","r","y","o","u","r",...]
使用flatMap而不是map:
Stream flatResult = words.stream().flatMap(w -> codePoints(w));
mapMuilt
mapMulit,每一个流都会调用mapper,并且所有在调用期间传递给Consumer的元素都会被添加到结果流中。
整体案例:
package streams;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class FilterMapFlatMapMapMuilt {
public static <T> void show(String title, Stream<T> stream) {
final int SIZE = 10;
List<T> firstElements = stream.limit(SIZE + 1).toList();
System.out.print(title + ": ");
for (int i = 0; i < firstElements.size(); i++) {
if (i > 0)
System.out.print(", ");
if (i < SIZE)
System.out.print(firstElements.get(i));
else
System.out.print("...");
}
System.out.println();
}
public static void main(String[] args) throws IOException {
Path path = Path.of("./resources/alice.txt");
var contents = Files.readString(path);
// 当使用\\PL+来分割字符串时,实际上是按照非字母字符序列来进行分割。
// 例如,对于字符串"hello,world!123",
// 使用\\PL+作为分割模式,会将字符串分割成["hello", "world", "123"]。
//可变参数,本质上是一个数组
List<String> words = List.of(contents.split("\\PL+"));
//filter过滤器,筛选出单词长度大于12的单词
Stream<String> longwords = words.stream().filter(w -> w.length()>12);
show("大于12个字母的长单词", longwords);
//map将所有单词转为大写,::是lamdba的紧凑形式,表示直接调用一个已存在的方法,而不用创建对象,简洁写法。
Stream<String> upperWords = words.stream().map(String::toUpperCase);
show("单词全大写字母", upperWords);
//map来截取所有单词的首字母,用lambda简化操作
Stream<String> firstLetters = words.stream().map(s -> s.substring(0,1));
show("单词的首字母", firstLetters);
//flatMap将所有的单词转化为单字母数组并摊平组成新的字母流。
//由于String.codePoints方法得到的是IntStream,形成整形流,无法直接转换为字符串,需要静态方法处理一下
Stream<String> flatResult = words.stream().flatMap(s -> codePoints(s));
show("flatResult", flatResult);
//上面给每一个元素都生成一个流,未免效率太低
//mapMulti可以提供一个流元素和收集器调用的函数,将函数结果传给收集器。
Stream<String> result = words.stream().mapMulti((s, collector) -> {
int i = 0;
while (i < s.length()) {
int cp = s.codePointAt(i);
collector.accept(new String(new int [] {cp},0,1));
//确定指定的字符(Unicode 代码点)是否在补充字符范围内,包括汉字等不是unicode范围内。
if(Character.isSupplementaryCodePoint(cp)) i+=2;//
else i++;
}
});
show("mapMulti",result);
}
private static Stream<String> codePoints(String s) {
//看api,如果直接转为long或者double可以,但要转为String需要mapToObj
return s.codePoints().mapToObj(cp -> new String(new int [] {cp},0,1));
}
}