java之Stream的常见用法

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象, 是一个来自数据源的元素队列并支持聚合操作(https://upload-images.jianshu.io/upload_images/6348370-f8218715507512e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

Stream 可以对集合和数组进行一些简化操作,将集合或数组转化为Stream流,使用Stream流中的方法对集合/数组中的元素进行操作,解决集合中的一些弊端

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

  • Pipelining:中间操作都会返回流对象本身,这样多个操作可以串联成一个管道,如果流式风格(fluent style),这样做可以对操作进行优化,比如延迟执行(laziness)和短路(short-circuiting)
  • 内部迭代:以前对集合遍历都是通过Iterator或者增强for的方式,显示的在集合外部进行迭代,这叫做外部迭代,Stream提供了内部迭代的方式,流可以直接调用遍历方法
  • 当使用一个流的时候,通常包括3个步骤:获取一个数据源(source) -> 数据转换 -> 执行操作获取想要的结果,每次转换原有Stream对象,返回一个新的Stream对象,这就允许对其操作可以向链条一样排列,变成一个管道
516E226E-0FFF-43E9-9283-779D9491EB38.png
  • Stream两种使用方法:
    1.在java.util.Collection 中有一个方法 default Stream
    2.java.util.stream接口的静态方法of可以获取数组对应的流
    static Stream of (T... values)
        List list = new ArrayList();
        Stream stream1 = list.stream();

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

        Map map = new HashMap();
        Set keySet= map.keySet();
        Stream stream3 = keySet.stream();

        Collection collection = map.values();
        Stream stream4 = collection.stream();

        // 获取键值对的映射关系
        // Map.entrySet() 这个方法返回的是一个Set>,Map.Entry 是Map中的一个接口,他的用途是表示一个映射项(里面有Key和Value),
        // 而Set>表示一个映射项的Set。Map.Entry里有相应的getKey和getValue方法,即JavaBean,让我们能够从一个项中取出Key和Value
        Set> entries = map.entrySet();
        Stream> stream = entries.stream();

        // 数组转换为stream流
        Integer[] arr = {1,2,3,4,5};
        Stream stream5= Stream.of(arr);
  • 案例1 : 对列表/数组中的每个元素都乘以2
package NewFeature.JavaStream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public static void main(String[] args) {
    int[] list = IntStream.range(1, 10).map(i -> i*2).toArray();
        for (int value: list) {
            System.out.println(value);
        }

    // or
    List result = IntStream.range(10, 20).map(i -> i*2).boxed().collect(Collectors.toList());
        for (int value: result) {
            System.out.println(value);
        }
}

输出:

2
4
6
8
10
12
14
16
18
  • 案例2:筛选重复元素
List list = Arrays.asList(1,2,2,3,4,2,1,5);
list.stream().filter(i -> i%2 == 0).distinct().forEach(System.out::println);

输出:

2
4
  • 选出以"张"开头、长度为3的名字
        List list = new ArrayList();
        list.add("张三丰");
        list.add("马可波诺");
        list.add("张小龙");
        list.add("赵无极");
        list.add("青龙");
        list.add("乔峰");

        List shortList = new ArrayList<>();
        for (String name:list) {
            if (name.length() == 3 && name.startsWith("张")) {
                shortList.add(name);
            }
        }
        System.out.println("张开头并且长度为2的名字=" + shortList.toString())
list.stream().filter(value -> value.startsWith("张"))
                .filter(value -> value.length() == 3)
                .collect(Collectors.toList()).forEach(System.out::print);
  • 案例3:限制元素数量
List list = Arrays.asList(2,5,6,6,8,2,12,63,53,13,76);
        list.stream().filter(i -> i>5).
                distinct().
                limit(3).
//                skip(1).
                collect(Collectors.toList()).
                forEach(System.out::println);

输出:

6
8
12

// 加了skip(1)
8
12
  • 案例4: Stream支持map方法,接收一个函数作为参数,这个函数被应用到每个元素上,并将其映射成一个新元素
List list = Arrays.asList("wudy", "macBook", "china hello");
        List wordLens = list.stream().map(String::length).collect(Collectors.toList());
        for (Integer item:wordLens) {
            System.out.println("长度=" + item);
        }

输出:

长度=4
长度=7
长度=11
  • 案例5:flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流
List list = Arrays.asList("Hello", "World");
        list.stream().map(word -> word.split(""))
                     .flatMap(Arrays::stream)
                     .distinct()
                     .collect(Collectors.toList())
                     .forEach(System.out::print)

输出:

HeloWrd

如下图:


B6AC3DC1-1866-434E-AF24-A4A6FA232579.png

-案例6:给定两个数字列表,返回所有的数对?例如:给定列表[1,3]、[2,4,6], 应该返回[(1,2),(1,4),(1,6),(3,2),(3,4),(3,6)]

List list1 = Arrays.asList(1,3);
        List list2 = Arrays.asList(2,4,6);
        List pairs = list1.stream().flatMap(i -> list2.stream()
                                          .map(j -> new int[] {i, j}))
                                          .collect(Collectors.toList());
        // pairs.stream().forEach(item -> Arrays.stream(item).forEach();
        for (int [] item: pairs) {
            System.out.println(Arrays.toString(item));
        }

输出:

[1, 2]
[1, 4]
[1, 6]
[3, 2]
[3, 4]
[3, 6]
  • 案例7: 匹配给定的谓词
List list = Arrays.asList("wudy","peter");
        if (list.stream().anyMatch(value -> value.equals("peter"))) {
            System.out.println("匹配到了给定的谓词");
        }

输出:

匹配到了给定的谓词
  • 案例8: 流中是否所有的元素能匹配给定的谓词
List list = Arrays.asList(5,7,11,423,54);
        if (list.stream().allMatch(value -> value > 3)) {
            System.out.println("匹配了所有的谓词");
        }

输出:

匹配了所有的谓词
  • 案例9: 流中没有任何元素能匹配给定的谓词
List list = Arrays.asList(101,198,112,423,354);
        if (list.stream().noneMatch(value -> value < 100)) {
            System.out.println("都能活到100岁");
        }

输出:

都能活到100岁
  • 案例10: 求Sum、max
List list = Arrays.asList(1,2,3,4,5,6);
//        Integer sum = list.stream().reduce(0, (a, b) -> a + b);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println("sum=" + sum);

        Integer max = list.stream().reduce(0, Integer::max);
        System.out.println("max=" + max);

输出:

sum=21
max=6
  • 案例11:现在有一个List集合,想对该集合中的数据分组处理
package NewFeature.JavaStream;

public class User {
    private  Integer id;
    private  Integer age;
    private  String name;

    public User(Integer id, Integer age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public Integer getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

}

package NewFeature.JavaStream;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 现在有一个List集合,想对该集合中的数据分组处理
 */
public class StreamDemo {
    public static void main(String[] args) {
        List list = getUserList();
        Map> userGroupList = list.stream().collect(Collectors.groupingBy(User::getAge));
        System.out.println(userGroupList);
//        for (Integer key: userGroupList.keySet()) {
//            System.out.println(userGroupList.get(key));
//        }
//
//        for (List value: userGroupList.values()) {
//            System.out.println(value);
//        }
    }

    public static ArrayList getUserList() {
        User user1 = new User(1, 18, "wudy");
        User user2 = new User(2, 20, "peter");
        User user3 = new User(3, 30, "timo");
        User user4 = new User(4, 20, "chimmy");

        ArrayList arrayList = new ArrayList();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        arrayList.add(user4);
        return arrayList;
    }
}

输出:

{18=[NewFeature.JavaStream.User@5b6f7412], 20=[NewFeature.JavaStream.User@27973e9b, NewFeature.JavaStream.User@312b1dae], 30=[NewFeature.JavaStream.User@7530d0a]}
  • Java8中Stream对列表去重的几种方法

1.distinct() 对于 String 列表的去重

 @Test
    public void stream1(){
        List list = new ArrayList<>();
        list.add("A");
        list.add("C");
        list.add("B");
        list.add("C");

        System.out.println("去重前=" + list);
        list = list.stream().distinct().collect(Collectors.toList());
        System.out.println("去重后=" + list);
    }
去重前=[A, C, B, C]
去重后=[A, C, B]

2.对实体类列表的去重

// 定义实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "message")
public class Message implements Serializable {
   @ApiModelProperty(value = "用户司机企业的id")
    private Long uid;

    @ApiModelProperty(value = "客服id")
    private String agentId;

    @ApiModelProperty(value = "客服名称")
    private String agentName;
}
// 实现类 MessageServiceImpl
package cn.huolala.llim.im.service.impl;


@Service
public class MessageServiceImpl extends ServiceImpl implements IMessageService {

    @Autowired
    private IMessageMapper iMessageMapper;

    @Override
    public List queryList(Message message, PageBO pager) {
        // 多条件构造器
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper
                .select("uid", "agent_id", "agent_name")  // 查询指定字段
                .isNotNull("uid").eq("uid", message.getUid());

        queryWrapper.orderByDesc("created_at");
        Page page = new Page<>(pager.getPage_no(), pager.getPage_size());
        page = iMessageMapper.selectPage(page, queryWrapper);
        return page.getRecords();
    }
}

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

 @Test
    public void stream() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Message message = new Message();
        message.setUid(113074491521L);

        PageBO page = new PageBO();
        page.setPage_no(1);
        page.setPage_size(10);

        // 1. 对于 Message 列表去重
        List messageList = iMessageService.queryList(message, page);
        System.out.println("去重前=" + messageList);
//        System.out.println("writeValueAsString = " + objectMapper.writeValueAsString(messageList));
        messageList = messageList.stream().distinct().collect(Collectors.toList());
        System.out.println("去重后=" + messageList);
//        System.out.println("writeValueAsString = " + objectMapper.writeValueAsString(messageList));

        messageList = messageList.stream().collect(
                collectingAndThen(
                        toCollection(() -> new TreeSet<>(Comparator.comparing(Message::getAgentId))), ArrayList::new)
        );
        System.out.println("根据agentID去重后=" + messageList);
    }
<==    Columns: uid, agent_id, agent_name
<==        Row: 113074491521, 107, wudy.yu2
<==        Row: 113074491521, 107, wudy.yu
<==        Row: 113074491521, 108, wudy.yu3
<==        Row: 113074491521, 107, wudy.yu


去重前=[Message(uid=113074491521, agentId=107, agentName=wudy.yu2), Message(uid=113074491521, agentId=107, agentName=wudy.yu), Message(uid=113074491521, agentId=108, agentName=wudy.yu3), Message(uid=113074491521, agentId=107, agentName=wudy.yu)]
去重后=[Message(uid=113074491521, agentId=107, agentName=wudy.yu2), Message(uid=113074491521, agentId=107, agentName=wudy.yu), Message(uid=113074491521, agentId=108, agentName=wudy.yu3)]
根据agentID去重后=[Message(uid=113074491521, agentId=107, agentName=wudy.yu2), Message(uid=113074491521, agentId=108, agentName=wudy.yu3)]


3.根据List中 Object 某个属性去重

// 见上例
messageList = messageList.stream().collect(
                collectingAndThen(
                        toCollection(() -> new TreeSet<>(Comparator.comparing(Message::getAgentId))), ArrayList::new)
        );

4.通过 filter() 方法

//我们首先创建一个方法作为 Stream.filter() 的参数,其返回类型为 Predicate,原理就是判断一个元素能否加入到 Set 中去,代码如下:

private static  Predicate distinctByKey(Function keyExtractor){
        Set seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }
 
 
 @Test
    public void stream() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Message message = new Message();
        message.setUid(113074491521L);

        PageBO page = new PageBO();
        page.setPage_no(1);
        page.setPage_size(10);

        // 1. 对于 Message 列表去重
        List messageList = iMessageService.queryList(message, page);
        System.out.println("去重前=" + messageList);
        messageList = messageList.stream().distinct().collect(Collectors.toList());
        System.out.println("去重后=" + messageList);

        //这里我们将 distinctByKey() 方法作为 filter() 的参数,过滤掉那些不能加入到 set 的元素
        messageList = messageList.stream().filter(distinctByKey(Message::getAgentId)).collect(Collectors.toList());
        System.out.println("根据agentID去重后=" + messageList);
    }
<==    Columns: uid, agent_id, agent_name
<==        Row: 113074491521, 107, wudy.yu2
<==        Row: 113074491521, 107, wudy.yu
<==        Row: 113074491521, 108, wudy.yu3
<==        Row: 113074491521, 107, wudy.yu
<==      Total: 4
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f6af096]
去重前=[Message(uid=113074491521, agentId=107, agentName=wudy.yu2), Message(uid=113074491521, agentId=107, agentName=wudy.yu), Message(uid=113074491521, agentId=108, agentName=wudy.yu3), Message(uid=113074491521, agentId=107, agentName=wudy.yu)]
去重后=[Message(uid=113074491521, agentId=107, agentName=wudy.yu2), Message(uid=113074491521, agentId=107, agentName=wudy.yu), Message(uid=113074491521, agentId=108, agentName=wudy.yu3)]
根据agentID去重后=[Message(uid=113074491521, agentId=107, agentName=wudy.yu2), Message(uid=113074491521, agentId=108, agentName=wudy.yu3)]
  • 案例1

如果有一个需求,需要对数据库查询到的菜肴进行一个处理:
筛选出卡路里小于400的菜肴
对筛选出的菜肴进行一个排序
获取排序后菜肴的名字

public class Dish {
    private String name;
    private boolean vegetarian;
    private int calories;
    private Type type;

    // getter and setter
}
// java8之前的实现方式
private List beforeJava7(List dishList) {
        List lowCaloricDishes = new ArrayList<>();

        //1.筛选出卡路里小于400的菜肴
        for (Dish dish : dishList) {
            if (dish.getCalories() < 400) {
                lowCaloricDishes.add(dish);
            }
        }

        //2.对筛选出的菜肴进行排序
        Collections.sort(lowCaloricDishes, new Comparator() {
            @Override
            public int compare(Dish o1, Dish o2) {
                return Integer.compare(o1.getCalories(), o2.getCalories());
            }
        });

        //3.获取排序后菜肴的名字
        List lowCaloricDishesName = new ArrayList<>();
        for (Dish d : lowCaloricDishes) {
            lowCaloricDishesName.add(d.getName());
        }

        return lowCaloricDishesName;
    }
// java8之后的实现方式
 private List afterJava8(List dishList) {
        return dishList.stream()
                .filter(d -> d.getCalories() < 400)  //筛选出卡路里小于400的菜肴
                .sorted(comparing(Dish::getCalories))  //根据卡路里进行排序
                .map(Dish::getName)  //提取菜肴名称
                .collect(Collectors.toList()); //转换为List
    }

高高兴兴写完需求这时候又有新需求了,新需求如下:
对数据库查询到的菜肴根据菜肴种类进行分类,返回一个Map>的结果
这要是放在jdk8之前肯定会头皮发麻

// java8之前的实现方式
private static Map> beforeJdk8(List dishList) {
    Map> result = new HashMap<>();

    for (Dish dish : dishList) {
        //不存在则初始化
        if (result.get(dish.getType())==null) {
            List dishes = new ArrayList<>();
            dishes.add(dish);
            result.put(dish.getType(), dishes);
        } else {
            //存在则追加
            result.get(dish.getType()).add(dish);
        }
    }

    return result;
}
// java8的实现方式
private static Map> afterJdk8(List dishList) {
    return dishList.stream().collect(groupingBy(Dish::getType));
}

一、什么是流?
流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算

二、如何生成流
生成流的方式主要有五种:

// 2.1>通过集合生成,应用中最常用的一种
List integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream stream = integerList.stream();
// 2.2>通过集合的stream方法生成流
// 2.2.1> 通过数组生成
int[] intArr = new int[]{1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(intArr);
/*
通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是Stream。
补充一点使用数值流可以避免计算过程中拆箱装箱,提高性能。Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流
【即Stream】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流
*/

// 2.2.2> 通过值生成
// 通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流
Stream stream = Stream.of(1, 2, 3, 4, 5);


// 2.3> 通过文件生成
// 通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行
Stream lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())

//2.4> 通过函数生成 
//提供了iterate和generate两个静态方法从函数中生成流
Stream stream = Stream.iterate(0, n -> n + 2).limit(5);

// iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数


Stream stream = Stream.generate(Math::random).limit(5);
//generate方法接受一个参数,方法参数类型为Supplier,
//由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断
  • 流的操作类型

流的操作类型主要分为两种:
1.中间操作 一个流可以后面跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时,常见的中间操作有下面即将介绍的filter、map等
2.终端操作 一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流。终端操作的执行,才会真正开始流的遍历。如下面即将介绍的count、collect等

参考资料: https://mp.weixin.qq.com/s?__biz=MzUxOTc4NjEyMw==&mid=2247506967&idx=2&sn=c9c4b190331dc53faf77f8185e9fd534&chksm=f9f6c7f3ce814ee59109d3f2496eae5feaa46ef09fbc098e2c0d02be591fdeb043a3389c0cbc&mpshare=1&scene=23&srcid=0427RZolHIHFZHAY2n3NoRkE&sharer_sharetime=1619505638932&sharer_shareid=f770d25bc57f1c2f9159f85750f854dc#rd

  • Stream对列表去重的几种方法
  • 1.Stream的distinct方法
    distinct()是Java 8 中 Stream 提供的方法,返回的是由该流中不同元素组成的流。distinct()使用 hashCode()eqauls() 方法来获取不同的元素。
    因此,需要去重的类必须实现 hashCode()equals() 方法。换句话讲,我们可以通过重写定制的 hashCode()equals()方法来达到某些特殊需求的去重。
    distinct() 方法声明如下:
  • 1.1 对String列表去重:
    因为 String 类已经覆写了 equals() 和 hashCode() 方法,所以可以去重成功
@Test
    public void distinct(){
        List stringList = new ArrayList(){
            {
                add("A");
                add("B");
                add("C");
                add("A");
            }
        };
        System.out.println("去重前:");
        for (String s : stringList){
            System.out.println(s);
        }

        stringList = stringList.stream().distinct().collect(Collectors.toList());

        System.out.println("去重后:");
        for (String s : stringList){
            System.out.println(s);
        }
    }

去重前:
A
B
C
A
去重后:
A
B
C

  • 1.2 对实体类列表的去重
    注:代码中我们使用了 Lombok 插件的 @Data注解,可自动覆写 equals() 以及 hashCode()方法
@Test
    public void distinct() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        List sList = new ArrayList<>();
        Student s1 = Student.builder().stuNo("001").name("wudy").build();
        Student s2 = Student.builder().stuNo("002").name("peter").build();
        Student s3 = Student.builder().stuNo("001").name("wudy").build();

        sList.add(s1);
        sList.add(s2);
        sList.add(s3);

        System.out.printf("去重前:" + mapper.writeValueAsString(sList));
        sList = sList.stream().distinct().collect(Collectors.toList());
        System.out.printf("去重后:" + mapper.writeValueAsString(sList));
    }

去重前:[{"stuNo":"001","name":"Tom"},{"stuNo":"002","name":"Mike"},{"stuNo":"001","name":"Tom"}]
去重后:[{"stuNo":"001","name":"Tom"},{"stuNo":"002","name":"Mike"}]

  • 1.3 根据List中Object某个属性去重
    import static java.util.stream.Collectors.collectingAndThen;
    import static java.util.stream.Collectors.toCollection;
    
     @Test
        public void test21() throws JsonProcessingException {
            List list = new ArrayList<>();
            Student s1 = Student.builder().stuNo("001").stuName("wudy").build();
            Student s2 = Student.builder().stuNo("002").stuName("peter").build();
            Student s3 = Student.builder().stuNo("001").stuName("wudy").build();
    
            list.add(s1);
            list.add(s2);
            list.add(s3);
    
            ObjectMapper mapper = new ObjectMapper();
            System.out.printf("去重前=" + mapper.writeValueAsString(list));
    
            list = list.stream().collect(
                    collectingAndThen(
                            toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getStuName))), ArrayList::new)
            );
    
            System.out.printf("去重后=" + mapper.writeValueAsString(list));
        }
    

    去重前=[{"stuName":"wudy","stuNo":"001"},{"stuName":"peter","stuNo":"002"},{"stuName":"wudy","stuNo":"001"}]
    去重后=[{"stuName":"peter","stuNo":"002"},{"stuName":"wudy","stuNo":"001"}]

    • 1.4 通过filter方法去重
    @Test
        public void test21() throws JsonProcessingException {
            List list = new ArrayList<>();
            Student s1 = Student.builder().stuNo("001").stuName("wudy").build();
            Student s2 = Student.builder().stuNo("002").stuName("peter").build();
            Student s3 = Student.builder().stuNo("001").stuName("wudy").build();
    
            list.add(s1);
            list.add(s2);
            list.add(s3);
    
            ObjectMapper mapper = new ObjectMapper();
            System.out.printf("去重前=" + mapper.writeValueAsString(list));
    
            // 将 distinctByKey() 方法作为 filter() 的参数,过滤掉那些不能加入到 set 的元素
            list = list.stream().filter(dictinctByKey(Student::getStuName)).collect(Collectors.toList());
    
            System.out.printf("去重后=" + mapper.writeValueAsString(list));
        }
    
        private static  Predicate dictinctByKey(Function keyExtractor){
            Set keys = ConcurrentHashMap.newKeySet();
            return t -> keys.add(keyExtractor.apply(t));
        }
     
     

    去重前=[{"stuName":"wudy","stuNo":"001"},{"stuName":"peter","stuNo":"002"},{"stuName":"wudy","stuNo":"001"}]
    去重后=[{"stuName":"wudy","stuNo":"001"},{"stuName":"peter","stuNo":"002"}]

    • Stream图解

    image.png

    Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等
    Stream可以由数组或集合创建,对流的操作分为两种:
    中间操作,每次返回一个新的流,可以有多个。
    终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
    另外,Stream有几个特性:

    • stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
    • stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
    • stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
    • 1.Stream创建:
      1.1> Stream可以通过集合数组创建,通过 java.util.Collection.stream() 方法用集合创建流
    List list = Arrays.asList("a", "b", "c");
    // 创建一个顺序流
    Stream stream = list.stream();
    // 创建一个并行流
    Stream parallelStream = list.parallelStream();
    

    1.2> 使用java.util.Arrays.stream(T[] array)方法用数组创建流

    int[] array={1,3,5,6,8};
    IntStream stream = Arrays.stream(array);
    

    1.3> 使用Stream的静态方法:of()、iterate()、generate()

    Stream stream = Stream.of(1, 2, 3, 4, 5, 6);
    
    Stream stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
    stream2.forEach(System.out::println); // 0 2 4 6 8 10
    
    Stream stream3 = Stream.generate(Math::random).limit(3);
    stream3.forEach(System.out::println);
    
    

    streamparallelStream的简单区分: stream顺序流,由主线程按顺序对流执行操作,而parallelStream并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处

    image.png
    • Stream的案例使用
      https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247539728&idx=2&sn=a3397ae7db0d7c13f21ae4d650b237ec&chksm=eb50d926dc275030a3ac919708b53af1a4bd339bce6e4f1351fd1eb88f9a5c2fdecdd2c6b02b&mpshare=1&scene=23&srcid=08216nSfljTSZcpp5Nql4z7m&sharer_sharetime=1629510377638&sharer_shareid=f770d25bc57f1c2f9159f85750f854dc%23rd

    • Stream简单案例

    https://mp.weixin.qq.com/s?__biz=MzUxOTc4NjEyMw==&mid=2247533024&idx=3&sn=393d7130c992ab67d5ce2dde66b165dc&chksm=f9f65a04ce81d312c3edc482d796f68b250e9bca943c77ce10e36e16e6a3c0850f10d58a7c24&mpshare=1&scene=23&srcid=0521nfdgr7cnkMhqRtFFGqz2&sharer_sharetime=1653147530521&sharer_shareid=7fec9c1809ccb850bfdebba7d4f7a81e%23rd
    
           // 1.list => 数组
            List arrayList = new ArrayList(Arrays.asList(1,3,5,7,9));
    //        int[] arr = arrayList.stream().mapToInt((item) -> Integer.valueOf(item)).toArray();
            int[] arr = arrayList.stream().mapToInt(Integer::intValue).toArray();
    
    
            for (int i=0;i k, k -> 1, Integer::sum))
                    .forEach((k, v) -> System.out.println(k + ": " + v));
    
    
            // 4.基本数据类型的数组自定义排序
            int[] arr4 = {1, 5, 9, 7, 2, 3, 7, -1, 0, 3};
            int[] arr5 = IntStream.of(arr4).boxed()
                          .sorted(Comparator.reverseOrder())
                          .mapToInt(Integer::intValue)
                          .toArray();
            for (Integer item:arr5) {
                System.out.println("item5="+ item);
            }
    
            // 5.统计数组中前 k 个个高频元素
            int[] arr6 = {1,3,2,55,33,3,6,1,55,3,2,0,98,3,1,41,52,2,1,3};
            int[] arr7 = Arrays.stream(arr6)
                    .boxed()
                    .collect(Collectors.toMap(e -> e, e -> 1, Integer::sum))
                    .entrySet()
                    .stream()
                    .sorted((m1, m2) -> m2.getValue() - m1.getValue())
                    .limit(2)
                    .mapToInt(Map.Entry::getKey)
                    .toArray();
    
            for (Integer item:arr7) {
                System.out.println("item7="+ item);
            }
    

    你可能感兴趣的:(java之Stream的常见用法)