到目前为止,我们已经将 Integer、Long 收集到了一个 Stream<Integer>、Stream<Long> 的流中,不过将每个整数包装成相应对象显然是一个低效的做法,对于其他原始类型 double、float、long、short、char、byte 及 boolean 也是一样。
为此,Java8 Stream API 提供了 IntStream、LongStream 和 DoubleStream 等类型,专门用来直接存储原始类型值,不必使用包装。
如果你想要存储 short、char、byte 和 boolean 类型的值,请使用 IntStream;而如果要存储 float 类型的值,请使用 DoubleStream。这是因为 Stream API 的设计者们认为,不需要为其他 5 种原始类型都添加对应的专门类型。
要创建一个 IntStream,你可以调用 Intstream.of 和 Arrays.stream 方法:
IntStream intStream = IntStream.of(1, 2, 3);
intStream.max().ifPresent(System.out::println);
//输出:3
Arrays.stream(new int[]{1, 2, 3}).max().ifPresent(System.out::println);
//输出:3对于对象流,你还可以使用静态的生成和迭代方法。除此之外,IntStream 和 LongStream 还拥有静态方法 range 和 rangeclosed,用来产生步长为1的一个整数范围。例如:
IntStream zeroToNinetyNine = IntStream.range(0,100); // 不包括上限 IntStream
System.out.println("sum=" + zeroToNinetyNine.sum());//sum=4950
IntStream zeroToHundred = IntStream.rangeClosed(0,100); // 包括上限
System.out.println("sum=" + zeroToHundred.sum()); //sum=5050CharSequence 接口有两个方法 codePoints 和 chars,可以生成包含字符 Unicode 代码的流,或者是包含 UTF-16 编码的代码单元的 IntStream。例如:
// \uD835\uDD46 是字母 ① 的 UTF-16 编码,unicode 是 U+1D546
String sentence = "\uD835\uDD46 is the set of octonions.";
IntStream codes = sentence.codePoints();
codes.forEach(e -> {
System.out.println(e + " = " + Integer.toHexString(e) + " = " + (char) e);
});
//输出:
//120134 = 1d546 = 핆
//32 = 20 =
//105 = 69 = i
//115 = 73 = s
//32 = 20 =
//116 = 74 = t
//104 = 68 = h
//101 = 65 = e
//32 = 20 =
//115 = 73 = s
//101 = 65 = e
//116 = 74 = t
//32 = 20 =
//111 = 6f = o
//102 = 66 = f
//32 = 20 =
//111 = 6f = o
//99 = 63 = c
//116 = 74 = t
//111 = 6f = o
//110 = 6e = n
//105 = 69 = i
//111 = 6f = o
//110 = 6e = n
//115 = 73 = s
//46 = 2e = .当你拥有一个对象流的时候,你可以通过 mapToInt、mapToLong 或者 mapToDouble 方法将它转换为一个原始类型流。例如,如果你有一个字符串流,并且希望按照它们的长度 (整型) 进行处理时,你可能会使用一个 IntStream:
List<String> list = Arrays.asList("one", "two", "three");
Stream<String> stream = list.stream();
int[] arrays = stream.mapToInt(String::length).toArray();
System.out.println(Arrays.toString(arrays));
//输出:[3, 3, 5]要将一个原始类型流转换为一个对象流,可以使用 boxed 方法:
List<String> list = Arrays.asList("one", "two", "three");
Stream<String> stream = list.stream();
// 得到原始类型流
IntStream intStream = stream.mapToInt(String::length);
// 将原始类型流转换为对象流
Stream<Integer> integerStream = intStream.boxed();
System.out.println(integerStream.collect(Collectors.toList()));
//输出:[3, 3, 5]一般来说,原始类型流上的方法与在对象流上调用的方法类似,但是有以下几点显著的区别:
toArray 方法会返回一个原始类型的数组,如:int[]。
产生 Optional 结果的方法会返回一个 OptionalInt、OptionalLong 或者 OptionalDouble 类型。这些类与 Optional 类类似,但是它们没有 get 方法,而是用对应的 getAsInt、getAsLong 和 getAsDouble 来代替。例如:
List<String> list = Arrays.asList("one", "two", "three");
OptionalInt opt = list.stream().mapToInt(String::length).max();
System.out.println(opt.getAsInt()); // 5方法 sum、average、max 和 min 会返回总和、平均值、最大值和最小值。在对象流中没有定义这些方法。
summaryStatistics 方法会产生一个 IntSummaryStatistics、LongSummaryStatistics 或者DoubleStummaryStatistics 对象,可以同时获得原始类型流的总和、平均值、最大值和最小值。例如:
List<String> list = Arrays.asList("one", "two", "three");
Stream<String> stream = list.stream();
// 得到原始类型流
IntStream intStream = stream.mapToInt(String::length);
IntSummaryStatistics statistics = intStream.summaryStatistics();
System.out.println("avg = " + statistics.getAverage());
System.out.println("count = " + statistics.getCount());
System.out.println("max = " + statistics.getMax());
System.out.println("min = " + statistics.getMin());
System.out.println("sum = " + statistics.getSum());
//输出:
//avg = 3.6666666666666665
//count = 3
//max = 5
//min = 3
//sum = 11注意:Random 类现在提供了 ints、longs 和 doubles 这些方法,用来返回包含随机数字的原始类型流。例如:
Random random = new Random(); // 生成10个 0~100 随机整数 int[] randoms = random.ints(10, 0, 100).toArray(); System.out.println(Arrays.toString(randoms)); //输出: //[41, 73, 58, 46, 95, 3, 29, 72, 57, 48]