Stream flow in java

Stream flow in java

Speaking Stream it is easy to think of I / O Stream, in fact, who prescribed "flow" it must be "IO stream" mean? In Java 8 in, thanks to functional programming Lambda brought about by the introduction of a new concept of Stream , has been used to solve the drawbacks of the existing library collections.

I. Introduction

Conventional multi-step through code set

Almost all of the set (e.g., Collectioninterface or Mapinterfaces, etc.) are directly or indirectly support the traversal operations. And when we need to operate elements of the collection, in addition to necessary to add, delete, get outside, typical is a collection of traversal.

Loop through drawbacks

Java Lambda 8 so that we can focus more on what to do (What), rather than how to do (How), this combination of inner classes had already carried out comparative illustration. Now, we carefully understand what the example code, you can find:

  • for loop syntax is " how to do "
  • loop for loop is "what to do "

Why cycling? Because to be traversed. But cycling is the only way to traverse it? Traversing means for processing each element individually, and not from the first cycle to the last of the sequential processing . The former is the goal, which is the way.

Imagine, if you want to set filter element filter:

  1. A set according to conditions of the filter as a subset of B ;

  2. The second condition is then filtered subset C .

    How to do that? In practice before 8 Java might be:

    public class Demo01List {
        public static void main(String[] args) {
    
            List<String> list = new ArrayList<>();
            list.add("张无忌");
            list.add("周芷若");
            list.add("赵敏");
            list.add("张强");
            list.add("张三丰");
    
            //对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
            List<String> listA = new ArrayList<>();
            for (String s : list) {
                if (s.startsWith("张")) {
                    listA.add(s);
                }
            }
    
            //对listA集合进行过滤,只要姓名长度为3的人,存储到一个新集合中
            List<String> listB = new ArrayList<>();
            for (String s : listA) {
                if (s.length() == 3) {
                    listB.add(s);
                }
            }
    
            //遍历listB集合
            for (String s : listB) {
                System.out.println(s);
            }
        }
    }

    This code contains three cycles, each of a different function:

    1. Zhang's first screened all people;
    2. Then there are the names of people screened three words;
    3. After the results are printed out.

    Whenever we need to set the elements to operate, always need to cycle, cycle, recycle. It is only natural it? No. Cycling is a way of doing things, not an end. On the other hand, using a linear traversal cycle means that only once. If you want to traverse again, and then use another cycle can only start from scratch.

    That, Lambda derivatives Stream can bring us what more elegant wording it?

Stream more preferably wording

The following look at the aid Java8 the Stream API, what is meant by elegant:

public class Demo02Stream {
    public static void main(String[] args) {
        //创建一个List集合,存储姓名
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        //对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
        //对listA集合进行过滤,只要姓名长度为3的人,存储到一个新集合中
        //遍历listB集合
        list.stream()
                .filter(name -> name.startsWith("张"))
                .filter(name -> name.length() == 3)
                .forEach(name -> System.out.println(name));
    }
}

Reading the code directly to the literal meaning of the semantic perfect display of logically independent: an acquisition stream, Zhang filtration, the filter length is 3, the printing one by one . The code does not reflect the use of linear cyclic or any other algorithm to traverse, we really need to do is to better reflect the contents of the code.

Second, the idea of ​​streaming overview

Note: Please Forget the stereotype of the traditional IO streams!
Overall, the streaming idea is similar to the factory floor, " production line ."

When the need for multiple elements to operate (especially multi-step operation), taking into account performance and convenience, we should first of all a good fight a "model" step program, and then follow the program to execute it.

This is shown in FIG filtering, mapping, skip, counting multiple operations, it is a process scheme of a collection of elements, while the program is a "function model." FIG Each block is a "flow", the method invokes the specified, another flow may be a flow model from the model conversion. 3 is a right-hand number and the final result.

Here filter 、 map 、 skipare the operation of the function model, and the set of elements is not actually processed. Only when the end of the method countwhen executed, the entire operation will be performed in accordance with the model specified policy. And thanks to the delay in the implementation of the Lambda characteristic.

Note: "Stream Flow" is actually a collection of elements of the model function, it is not set, the data structure is not, in itself does not store any element (or address value).

Stream (flow) is an element from the data source queue

  • Element is a particular type of object, a queue is formed. In Java Stream and does not store elements, but on-demand computing.
  • 数据源 流的来源。 可以是集合,数组 等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者增强for的方式, 显式的在集合外部进行迭代, 这叫做外部迭 代。 Stream提供了内部迭代的方式,流可以直接调用遍历方法。

当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换→执行操作获取想要的结 果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以 像链条一样排列,变成一个管道。

三、获取流

java.util.stream.Stream<T> 是Java 8新加入的常用的流接口。(这并不是一个函数式接口。)
获取一个流非常简单,有以下几种常用的方式:

  • 所有的 Collection 集合都可以通过 stream 默认方法获取流;

  • Stream 接口的静态方法 of 可以获取数组对应的流。

根据Collection & Map & Array 获取流 &

首先, java.util.Collection 接口中加入了default方法 stream 用来获取流,所以其所有实现类均可获取流。

java.util.Map 接口不是 Collection 的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流 需要分key、value或entry等情况:

如果使用的不是集合或映射而是数组,由于数组对象不可能添加默认方法,所以 Stream 接口中提供了静态方法 of ,使用很简单:

备注: of 方法的参数其实是一个可变参数,所以支持数组。

/*
    java.util.stream.Stream<T>是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)
    获取一个流非常简单,有以下几种常用的方式:
        - 所有的Collection集合都可以通过stream默认方法获取流;
            default Stream<E> stream​()
        - Stream接口的静态方法of可以获取数组对应的流。
            static <T> Stream<T> of​(T... values)
            参数是一个可变参数,那么我们就可以传递一个数组
 */
public class Demo01GetStream {
    public static void main(String[] args) {
        //把集合转换为Stream流
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> stream2 = set.stream();

        Map<String,String> map = new HashMap<>();
        //获取键,存储到一个Set集合中
        Set<String> keySet = map.keySet();
        Stream<String> stream3 = keySet.stream();

        //获取值,存储到一个Collection集合中
        Collection<String> values = map.values();
        Stream<String> stream4 = values.stream();

        //获取键值对(键与值的映射关系 entrySet)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> stream5 = entries.stream();

        //把数组转换为Stream流
        Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
        //可变参数可以传递数组
        Integer[] arr = {1,2,3,4,5};
        Stream<Integer> stream7 = Stream.of(arr);
        String[] arr2 = {"a","bb","ccc"};
        Stream<String> stream8 = Stream.of(arr2);
    }
}

四、常用方法

流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

  • 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方 法均为延迟方法。)
  • 终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样的链式调 用。本小节中,终结方法包括 countforEach 方法。

备注:本小节之外的更多方法,请自行参考API文档。

逐一处理:forEach

虽然方法名字叫 forEach ,但是与for循环中的“for-each”昵称不同。

 void forEach(Consumer<? super T> action);

该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理。

基本使用:

public class Demo02Stream_forEach {
    public static void main(String[] args) {
        //获取一个Stream流
        Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");
        stream.forEach(name->System.out.println(name));
    }
}

过滤:filter

可以通过 filter 方法将一个流转换成另一个子集流。方法签名:

    Stream<T> filter(Predicate<? super T> predicate);

该接口接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件

基本使用:

/*
    Stream流中的常用方法_filter:用于对Stream流中的数据进行过滤
    Stream<T> filter(Predicate<? super T> predicate);
    filter方法的参数Predicate是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
    Predicate中的抽象方法:
        boolean test(T t);
 */
public class Demo03Stream_filter {
    public static void main(String[] args) {
        //创建一个Stream流
        Stream<String> stream = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
        //对Stream流中的元素进行过滤,只要姓张的人
        Stream<String> stream2 = stream.filter((String name)->{return name.startsWith("张");});
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));

        /*
            Stream流属于管道流,只能被消费(使用)一次
            第一个Stream流调用完毕方法,数据就会流转到下一个Stream上
            而这时第一个Stream流已经使用完毕,就会关闭了
            所以第一个Stream流就不能再调用方法了
            IllegalStateException: stream has already been operated upon or closed
         */
        //遍历stream流
        stream.forEach(name-> System.out.println(name));
    }
}

映射:map

如果需要将流中的元素映射到另一个流中,可以使用 map 方法。方法签名:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流,称为映射。

基本使用

public class Demo04Stream_map {
    public static void main(String[] args) {
        //获取一个String类型的Stream流
        Stream<String> stream = Stream.of("1", "2", "3", "4");
        //使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数
        Stream<Integer> stream2 = stream.map((String s)->{
            return Integer.parseInt(s);
        });
        //遍历Stream2流
        stream2.forEach(i-> System.out.println(i));
    }
}

统计个数:count

正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数:

long count();

该方法返回一个long值代表元素个数(不再像旧集合那样是int值)。

基本使用:

public class Demo05Stream_count {
    public static void main(String[] args) {
        //获取一个Stream流
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        Stream<Integer> stream = list.stream();
        long count = stream.count();
        System.out.println(count);//输出7
    }

取用前几个:limit

`limit方法可以对流进行截取,只取用前n个,方法签名:

    Stream<T> limit(long maxSize);

基本使用:

public class Demo06Stream_limit {
    public static void main(String[] args) {
        //获取一个Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
        Stream<String> stream = Stream.of(arr);
        //使用limit对Stream流中的元素进行截取,只要前3个元素
        Stream<String> stream2 = stream.limit(3);
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));
    }
}

跳过前几个:skip

如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流:

  Stream<T> skip(long n);

如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。

基本使用:

public class Demo07Stream_skip {
    public static void main(String[] args) {
        //获取一个Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
        Stream<String> stream = Stream.of(arr);
        //使用skip方法跳过前3个元素
        Stream<String> stream2 = stream.skip(3);
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));
    }
}
// 灰太狼
// 红太狼

组合:concat

如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat

    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);

        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }

基本使用:

public class Demo08Stream_concat {
    public static void main(String[] args) {
        //创建一个Stream流
        Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
        //获取一个Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
        Stream<String> stream2 = Stream.of(arr);
        //把以上两个流组合为一个流
        Stream<String> concat = Stream.concat(stream1, stream2);
        //遍历concat流
        concat.forEach(name-> System.out.println(name));
    }
}

Guess you like

Origin www.cnblogs.com/heliusKing/p/10990221.html