StramApi常用操作

StramApi常用操作

什么是流 ?

Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。

Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返.

流的结构

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

流管道 (Stream Pipeline) 的构成

在这里插入图片描述

生成 Stream Source的方式

从 Collection 和数组

Collection.stream()
Collection.parallelStream()
Arrays.stream(T array) or Stream.of()

从 BufferedReader

java.io.BufferedReader.lines()

静态工厂

java.util.stream.IntStream.range()
java.nio.file.Files.walk()

自己构建

java.util.Spliterator

其它

Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()
流的操作类型分为两种:

Intermediate(中间):一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

Terminal(最终):一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
在对于一个 Stream 进行多次转换操作 (Intermediate 操作),每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。

一个流操作的示例

int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
 .mapToInt(w -> w.getWeight())
 .sum();

stream() 获取当前小物件的 source,filter 和 mapToInt 为 intermediate 操作,进行数据筛选和转换,最后一个 sum() 为 terminal 操作,对符合条件的全部小物件作重量求和。

构造流的几种常见方法

// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();

1.流转换为其它数据结构

1.1 转为数组 Array
String[] arr=Stream.toArray(String[]::new)

代码:

private static  List<Person> getList() {
    List<Person> list = new ArrayList<>();
    list.add(new Person("范冰冰","女",28));
    list.add(new Person("刘亦菲","女",24));
    list.add(new Person("胡歌","男",30));
    return list;
}

public static void main(String[] args) {
    List<Person> list = getList();
    //list 转 数组
    Person[] arr= list.stream().toArray(Person[]::new);
    Arrays.stream(arr).forEach(System.out::println);
}

效果:
在这里插入图片描述

1.2 转为集合 list,set Collection
List<String> list = stream.collect(Collectors.toList());
List<String> list = stream.collect(Collectors.toCollection(ArrayList::new));
Set set = stream.collect(Collectors.toSet());
Stack stack = stream.collect(Co`llectors.toColl`ection(Stack::new));

代码:

  public static void main(String[] args) {
    List<Person> list = getList();
    //list 转 数组
    Person[] arr= list.stream().toArray(Person[]::new);
    //数组 转 list
    List<Person> collect = Arrays.stream(arr).collect(Collectors.toList());
}
1.3 转为字符串
String str = stream.collect(Collectors.joining()).toString();
//Collectors.joining 收集器 支持灵活的参数配置,可以指定字符串连接时的 分隔符,前缀 和 后缀 字符串

代码:

final static String[] names = {"A", "B", "C", "D", "E"};
public static void main(String[] args) {
    String collect = Stream.of(names).collect(Collectors.joining("-", "{", "}"));
    System.out.println("字符串格式="+collect);
}

效果图:

在这里插入图片描述

2.流的操作

流的操作
接下来,当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。
Intermediate:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
Terminal:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

常用操作:

map: 把 input Stream 的每一个元素,映射成 output Stream 的另外一个元素。

在项目中的应用:

1.list对象转换为某个属性的list字符串 (用来取list对象中的所有的对象的某个属性的list)

private static  List<Person> getList() {
        List<Person> list = new ArrayList<>();
        list.add(new Person("范冰冰","女",28));
        list.add(new Person("刘亦菲","女",24));
        list.add(new Person("胡歌","男",30));
        return list;
    }

    public static void main(String[] args) {
        //获取所有的学生名字
        List<Person> list = getList();
        List<String> resList = list.stream().map(Person::getName).collect(Collectors.toList());
        resList.stream().forEach(System.out::println);
    }

在这里插入图片描述
2.list对象转化为某两个属性拼接的list字符串

public static void main(String[] args) {
        //获取所有人  "名字+年龄" 格式 的list
        List<Person> list = getList();
        List<String> resList = list.stream().map(e -> e.getName()+"+"+e.getAge()).collect(Collectors.toList());
        resList.stream().forEach(System.out::println);
    }

在这里插入图片描述
3.list对象按照某个属性值进行分组

 private static  List<Person> getList() {
        List<Person> list = new ArrayList<>();
        list.add(new Person("范冰冰","女",28));
        list.add(new Person("刘亦菲","女",24));
        list.add(new Person("胡歌","男",30));
        list.add(new Person("胡歌","女",24));
        return list;
    }

    public static void main(String[] args) {
        //根据名字进行分组
        List<Person> list = getList();
        Map<Integer, List<Person>> collect = list.stream().collect(Collectors.groupingBy(Person::getAge));
        Set<Map.Entry<Integer, List<Person>>> entries = collect.entrySet();
        for(Map.Entry<Integer, List<Person>> entity:entries){
            System.out.println("key="+entity.getKey()+"value="+entity.getValue().size());
        }

    }

在这里插入图片描述
4.list对象按照某两个属性拼接进行分组


    private static  List<Person> getList() {
        List<Person> list = new ArrayList<>();
        list.add(new Person("范冰冰","女",28));
        list.add(new Person("刘亦菲","女",24));
        list.add(new Person("胡歌","男",24));
        list.add(new Person("胡歌","女",24));
        return list;
    }

    public static void main(String[] args) {
        //根据 "性别-年龄" 格式进行分组
        List<Person> list = getList();
        Map<String, List<Person>> collect = list.stream().collect(Collectors.groupingBy(e -> e.getGender() + "-" + String.valueOf(e.getAge())));
        Set<Map.Entry<String, List<Person>>> entries = collect.entrySet();
        for(Map.Entry<String, List<Person>> entity:entries){
            System.out.println("key="+entity.getKey()+"  value="+entity.getValue().size());
        }

    }

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章