Java8 Stream流遍历 使用其自带的索引遍历

Java8Stream流为我们的遍历集合带来了方便,基本可以取代for循环了。但是有一些情况需要知道当前遍历的索引,使用for循环当然可以轻易获得,但使用stream就很难了。但是并不是没有办法的事,如下所示

一,代码示例

1)Lambda.class

package com.example.demo.main;

import com.example.demo.Bean.Food;
import com.example.demo.Bean.User;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Lambda {

    public static void main(String[] args) {

        IntStream.of(7, 2, 3, 4, 5, 6, 9).map(elem -> elem * 10).forEach(System.out::println);

        List users = new ArrayList<>();
        User user = new User(5L, "name5", new Food(5L, "food1", 5));
        User user2 = new User(3L, "name3", new Food(3L, "food2", 3));
        User user3 = new User(4L, "name4", new Food(4L, "food3", 4));
        User user4 = new User(9L, "name9", new Food(9L, "food4", 9));
        User user5 = new User(7L, "name7", new Food(7L, "food5", 7));
        users.add(user);
        users.add(user2);
        users.add(user3);
        users.add(user4);
        users.add(user5);
        // 首先根据user的id进行排序
        List sortedUsers = users.stream()
                .sorted(Comparator.comparingLong(User::getId))
                .collect(Collectors.toList());
        
        // 然后将排序后的user的Food的num的值改为排序后的索引位置赋值
        // 使用IntStream流来构造一个Int类型的流出来,然后遍历这个Int的流,list中的对象可以通过get方法来取。其中modifyFoodNum(sortedUsers.get(i),i)成功的将索引带到了方法中
        // 需要注意的是:在流中必须使用mapToObj,而不能使用map映射,也不能省去collect(...)方法
        IntStream.range(0, sortedUsers.size()).mapToObj(i -> modifyFoodNum(sortedUsers.get(i), i)).collect(Collectors.toList());

        sortedUsers.stream().forEach(System.out::println);
    }

    public static User modifyFoodNum(User user, int i) {
        Food food = user.getFood();
        System.out.println("i的当前值为:" + i);
        food.setNum(i + 1);
        return user;
    }

}

2) Food类:

package com.example.demo.Bean;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Food {

    private Long id;

    private String name;

    private Integer num;

    public Food(Long id, String name, Integer num) {
        this.id = id;
        this.name = name;
        this.num = num;
    }

    @Override
    public String toString() {
        return "Food{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", num=" + num +
                '}';
    }
}

3)User类:

package com.example.demo.Bean;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class User {

    private Long id;
    private String name;
    private Food food;

    public User(Long id, String name, Food food) {
        this.id = id;
        this.name = name;
        this.food = food;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", food=" + food +
                '}';
    }
}

二,map映射和mapToObj的区别

首先Stream流下面的类包含了IntStream, LongStream, DoubleStream

  1. 那么究竟下面两者有什么区别呢?
Stream // 包装类型
IntStream   //基本类型

所以对于mapToObjmapToInt也是同样的
mapToObj 方法主要是将Stream中的元素进行装箱操作, 转换成一个引用类型的值。
mapToInt 方法是将Stream中的 元素转换成基本类型int
比如下面的例子

Stream s = IntStream.of(4, 5, 6).mapToObj(e -> e); //mapToObj method is needed
IntStream is = Stream.of(4, 5, 6).mapToInt(e -> e); //mapToInt method is needed

可以看到Stream是包装类型,所以想要把IntStream基本类型流转化成包装类型,就需要使用mapToObj

  1. 上面两个mapToObj和mapToInt是进行类型的转化,那么map的作用呢?
    map不进行类型转化,如果原来流中是基本类型,map映射完应当还是基本类型,如果原来是包装类型,映射完应当还是包装类型
    比如下面这个例子:
IntStream.of(7, 2, 3, 4, 5, 6, 9).map(elem -> elem * 10).forEach(System.out::println);

这也就解释了,为什么上面的第二节解决办法里面,用map不行,而需要mapToObj,因为那里做了一个基本类型到包装类型的转化

三. 总结

  1. 使用IntStream可以灵活的操作对象和获取索引。
  2. map不进行包装和基本类型的转化,mapToObj是基本转为包装,mapToInt是包装转为基本。

参考:https://www.jianshu.com/p/183b3d1c30a2

你可能感兴趣的:(01,JAVA)