Java8 Stream Detailed and practical new features

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/wo541075754/article/details/102458705

Java8 Stream Detailed and practical new features

Background

In reading Spring Boot source code and found the new features of Java 8 has been widely used, if we do not learn the new features Java8 and flexible application, you might really want out of. To this end, new features for Java8, it will update a series of articles, we welcome the continued attention.

First, we look at a piece of code Spring Boot source code ConfigFileApplicationListener class:

private List<Profile> getOtherActiveProfiles(Set<Profile> activatedViaProperty) {
	return Arrays.stream(this.environment.getActiveProfiles()).map(Profile::new)
			.filter((profile) -> !activatedViaProperty.contains(profile))
			.collect(Collectors.toList());
}

This code how? Simple and neat enough of it, if you do not use the new features Java8, imagine how many lines of code have to be achieved? But if you do not grasp or understand Java8 of new features, read this code is not very sour cool?

Java API 8 to add the abstraction of a set of processing: Stream, Chinese referred to as "flow." It can specify that you want a set of operations performed, can perform very complex search, filtering and mapping data and other operations. Use it like to use SQL statements to perform database query operations on the same. It allows you to fill the gap in general to write simple, efficient and energetic code.

What is Stream

Stream Chinese called "flow", by the so called set is converted to "flow" sequence of elements (note the abstraction), can be performed in parallel or serial number of each element in the set by way of a declarative pipelining. Popular, that is, you only told the "flow" of what you need, then wait for the results of the interface at the exit.

Here Insert Picture Description
The picture shows the basic flow of Steam operation can be repeated with a particular control code after the learning process, the learning deeper impression.

Stream concepts

Stream operation of the process involved in a number of related concepts, first look, convenient unified behind the title.

  • Element: specific types of objects, such as List object placed inside, form a queue. Stream does not store elements, but on-demand computing.
  • 数据源:流的来源,对照上图中的集合,数组,I/O channel, 产生器generator等。
  • 聚合操作:类似SQL语句的各种过滤操作,对照上图中的filter、sorted、map等。
  • Pipelining:中文词义“流水线”,中间操作会返回流本身,跟我们之前所说的流式(fluent)编程一个概念,这样可对操作进行优化,比如延迟执行(laziness)和短路(short-circuiting)。
  • 内部迭代:传统遍历方式是通过Iterator或For-Each来完成,这是外部迭代。而Stream通过访问者模式(Visitor)实现了内部迭代。

需要注意的是在整个操作的过程中,聚合操作部分可以执行多次操作,但每次操作并不是像传统的集合遍历对集合里面的元素进行转换,而是将操作函数放入一个操作集合中,只有到最后一步(比如for-each打印)时才会一次性执行。

而流和迭代器类似,只能迭代一次。比如,当调用完collect方法之后,流便不能再使用了。

stream操作方法分类

中间聚合操作:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 skip、 parallel、 sequential、 unordered。

最终输出操作:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、iterator。

短路操作:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit。

生成流

在 Java 8 中, 生成流有多种方法:Stream接口的静态工厂方法、集合提供的生成方法和其他特殊的生成方法。

of方法

Stream接口的静态工厂方法主要通过重载的of方法:

public static<T> Stream<T> of(T... values);

public static<T> Stream<T> of(T t)

of方法,其生成的Stream是有限长度的,Stream的长度为其内的元素个数。使用示例代码:

Stream<String> stringStream = Stream.of("公众号");
Stream<String> stringsStream = Stream.of("关注","公众号", "程序新视界");

generator方法

与of方法对应的generator方法生成的是无限长度的Stream,其元素是由Supplier接口提供的。

public static<T> Stream<T> generate(Supplier<T> s)

使用generate方法生成的Stream通常用于随机数和常量,或者需要前后元素间维持着某种状态信息的场景。把 Supplier 实例传递给 Stream.generate() 生成的 Stream,默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。

示例代码如下:

Stream<Double> generateDouble = Stream.generate(Math::random);

Stream<String> generateString = Stream.generate(new Supplier<String>() {
	@Override
	public String get() {
		return "公众号:程序新视界";
	}
});

其实上面两种写法的效果是一样的,只不过第一种采用了Lambda表达式,简化了代码。

iterate方法

iterate方法生成的也是无限长度的Stream,是通过函数f迭代对给指定的元素种子而产生无限连续有序Stream,其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。示例代码如下:

Stream.iterate(1,i -> i +1).limit(10).forEach(System.out::println);

打印结果为1,2,3,4,5,6,7,8,9,10。

上面的方法可以认为种子(seed)为1,f(seed)为在1的基础上“+1”,依次循环下去,直到达到limit的限制,最后生成对应的Stream。

empty方法

empty方法生成一个空的Stream,不包含任何元素。

Collection接口和数组的默认方法

Collection接口和数组中都提供了默认的生成Stream的方法。直接看源代码:

// Collection中
default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}
// 并行流操作
default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

// Arrays中
public static <T> Stream<T> stream(T[] array) {
    return stream(array, 0, array.length);
}

public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
    return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
}

示例代码:

List<String> list = new ArrayList<>();
list.add("欢迎关注");
list.add("微信公众号");
list.add("程序新视界");
list.stream().forEach(System.out::println);

int[] nums = new int[]{1, 2, 3, 4, 5};
Arrays.stream(nums).forEach(System.out::println);

其他生成方法

关于其他生成方法就不详细举例了,比如:Random.ints()、BitSet.stream()、JarFile.stream()、Pattern.splitAsStream(java.lang.CharSequence)、Files.lines(java.nio.file
.Path)等。

操作方法使用

关于操作方法就不进行详细的讲解,更多的以示例的形式展示如何使用。

concat方法

合并两个Stream。如果输入Stream有序,则新Stream有序;如果其中一个Stream为并行,则新Stream为并行;如果关闭新Stream,原Stream都将执行关闭。

Stream.concat(Stream.of("欢迎","关注"),Stream.of("程序新视界")).forEach(System.out::println);

distinct

Stream中元素去重。

Stream.of(1,1,1).distinct().forEach(System.out::println);

打印结果为1。

filter

根据指定条件进行筛选过滤,留下满足条件的元素。

Stream.of(1, 2, 3, 4, 5).filter(i -> i >= 3).forEach(System.out::println);

打印结果为3,4,5。

map

将Stream中的元素进行映射转换,比如将“a”转为“A”,期间生产了新的Stream。同时为了提升效率,官方也提供了封装好的方法:mapToDouble,mapToInt,mapToLong。

Stream.of("a","b","c").map(item -> item.toUpperCase()).forEach(System.out::println);
Stream.of("a","b","c").map(String::toUpperCase).forEach(System.out::println);

打印结果为A,B,C。

flatMap

将流中的每一个元素映射为一个流,再把每一个流连接成为一个流。期间原有的Stream的元素会被逐一替换。官方提供了三种原始类型的变种方法:flatMapToInt,flatMapToLong和flatMapToDouble。

Stream.of(1, 2, 3).flatMap(i -> Stream.of(i * 10)).forEach(System.out::println);

打印结果为10,20,30。

peek

生成一个相同的Stream,并提供一个消费函数,当新Stream中的元素被消费(执行操作)时,该消费函数会在此之前先执行。

Stream.of(1, 2).peek(i -> System.out.println("peekCall:" + i)).forEach(System.out::println);

打印结果依次为:peekCall:1,1,peekCall:2,2。

ship

跳过前N个元素,取剩余元素,如果没有则为空Stream。

Stream.of(1, 2, 3).skip(2).forEach(System.out::println);

打印结果为3。

sorted

对Stream元素进行排序,可采用默认的sorted()方法进行排序,也可通过sorted(Comparator)方法自定义比较器来进行排序,前者默认调用equals方法来进行比较,

Stream.of(1, 3, 2).sorted().forEach(System.out::println);

打印结果:1,2,3。

limit

限制返回前N个元素,与SQL中的limit相似。

Stream.of(1, 2, 3).limit(2).forEach(System.out::println);

打印结果为:1,2。

collect

收集方法,实现了很多归约操作,比如将流转换成集合和聚合元素等。

Stream.of(1, 2, 3).collect(Collectors.toList());
Stream.of(1, 2, 3).collect(Collectors.toSet());

除了以上的集合转换,还有类似joining字符串拼接的方法,具体可查看Collectors中的实现。

count

返回Stream中元素个数。

Stream.of(1, 2, 3).count();

forEach

遍历Stream中所有元素。示例参考以上设计到的。

forEachOrder

遍历Stream中所有元素,如果Stream设置了顺序,则按照顺序执行(Stream是无序的),默认为元素的插入顺序。

max

根据指定的比较器(Comparator),返回Stream中最大元素的Optional对象,Optional中的value便是最大值。

Optional可以代表一个值或不存在,主要是为了规避返回值为null,而抛出NullPointerException的问题,也是由Java8引入的。但当调用其get()方法时,如果当前值不存在则会抛出异常。

Optional<Integer> max = Stream.of(1, 2, 3).max(Comparator.comparingInt(o -> o));
System.out.println("max:" + max.get());

打印结果:max:3。

min

与max操作相同,功能相反,取最小值。

Optional<Integer> min = Stream.of(1, 2, 3).min(Comparator.comparingInt(o -> o));
System.out.println("min:" + min.get());

打印结果:min:1。

reduce

reduce可实现根据指定的规则从Stream中生成一个值,比如之前提到的count,max和min方法是因为常用而被纳入标准库中。实际上,这些方法都是reduce的操作。

Stream.of(1, 2, 3).reduce(Integer::sum);
Stream.of(1, 2, 3).reduce(0, (a, b) -> a + b);

以上两个方法都是对结果进行求和,不同的是第一个方法调用的是reduce的reduce((T, T) -> T)方法,而第二个调用的是reduce(T, (T, T) -> T)。其中第二个方法的第一个参数0,表示从第0个值开始操作。

allMatch

判断Stream中的所有元素是否满足指定条件。全部满足返回true,否则返回false。

boolean result = Stream.of(1, 2, 3).allMatch(i  -> i > 0);
System.out.println(result);

返回结果:true。

anyMatch

判断Stream中的元素至少有一个满足指定条件。如果至少有一个满足则返回true,否则返回false。

boolean anyResult = Stream.of(1, 2, 3).anyMatch(i  -> i > 2);
System.out.println(anyResult);

返回结果:true。

findAny

获得其中一个元素(使用stream()时找到的是第一个元素;使用parallelStream()并行时找到的是其中一个元素)。如果Stream为空,则返回一个为空的Optional。

Optional<String> any = Stream.of("A", "B", "C").findAny();
System.out.println(any.get());

返回结果:A。

findFirst

获得第一个元素。如果Stream为空,则返回一个为空的Optional。

Optional<String> first = Stream.of("A", "B", "C").findFirst();
System.out.println(first.get());

返回结果:A。

noneMatch

判断Stream中是否所有元素都不满足指定条件。都不满足则返回true,否则false。

boolean noneMatch = Stream.of(1, 2, 3).noneMatch(i  -> i > 5);
System.out.println(noneMatch);

返回结果:true。

统计

通过summaryStatistics方法可获得Stream的一些统计信息。

IntSummaryStatistics summaryStatistics = Stream.of(1, 2, 3).mapToInt((i) -> i).summaryStatistics();
System.out.println("max:" + summaryStatistics.getMax());
System.out.println("min:" + summaryStatistics.getMin());
System.out.println("sum:" + summaryStatistics.getSum());
System.out.println("average:" + summaryStatistics.getAverage());

Here used directly in stream stream conversion mapToInt, there are a method analogous mapToDouble, mapToLong. The corresponding values ​​obtained flow also provides some additional methods, different methods to obtain statistical information as shown above.

Aerial view Stream

Finally, we'll look at the main interface to the Stream class diagram.
Here Insert Picture Description
Wherein, BaseStream defines a basic interface of the Stream, Stream defined map, filter, flatMap other common operations. IntStream, LongStream, DoubleStream is to provide a convenient and specialized operations on basic types. Interface built above the foundation Java8 flow system. AbstractPipeline pipelining (the Pipeline) core abstract class for building and managing the pipeline.

In addition, with regard to the efficiency of Stream Online also has a lot of information mentioned in the next article, we will focus here Stream of performance issues, public concern number "program New Horizons", so stay tuned.

Original link: " Java8 Stream Detailed new features and practical "


New Horizons program

Watch programmer career, a lot of high-quality learning resources, share technical articles

csdn- micro-channel public number

Guess you like

Origin blog.csdn.net/wo541075754/article/details/102458705
Recommended