2

数值流:

数值流,顾名思义就是专门用来操作基础数据类型的流,那它的作用是什么呢?先看下面的代码。这段代码是获取集合每个对象的num字段的值,然后求所和。得出的结果是15,看上去没有问题,但是要注意的是流在进行求和操作的时候从对象中取出来的是基本类型,会进行装箱操作变成Integer类型再进行求和,性能会有所下降,而数值流就是专门对基本类型数据进行操作的。

public class DataStream {
    public static void main(String[] args){
        List<Num> list = new ArrayList<Num>();
        Num num1 = new Num(1);
        Num num2 = new Num(2);
        Num num3 = new Num(3);
        Num num4 = new Num(4);
        Num num5 = new Num(5);
        list.add(num1);
        list.add(num2);
        list.add(num3);
        list.add(num4);
        list.add(num5);
        System.out.println(list.stream().map(Num::getNum).reduce(Integer::sum));
    }
}

class Num{
    private int num;

    public Num(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

数值流的使用:

1.想要使用数值流其实很简单,只需要调用Stream.mapToInt()方法就可以获得一个数值流了,我们会发现数值流有更多的封装好的计算方法,更加方便我们对数值的计算。

System.out.println(list.stream().mapToInt(Num::getNum).count());
System.out.println(list.stream().mapToInt(Num::getNum).sum());
System.out.println(list.stream().mapToInt(Num::getNum).max());
System.out.println(list.stream().mapToInt(Num::getNum).min());
System.out.println(list.stream().mapToInt(Num::getNum).average());

运行结果:

5
15
OptionalInt[5]
OptionalInt[1]
OptionalDouble[3.0]

2.需要注意的是maxminaverage方法如果在流为空的时候获取不到值会返回空的Optional对象,而countsum方法则是返回0。

运行结果:

0
0
OptionalInt.empty
OptionalInt.empty
OptionalDouble.empty

3.有时候我们可能会想将数值流转换回原来的流,我们可以调用boxed()方法。

public static void changeStream(){
    int[] arr = new int[]{1,2,3,4,5};
    IntStream intStream =  Arrays.stream(arr);
    Stream<Integer> stream = intStream.boxed();
}

4.上面我们介绍的是IntStream,它专门用来处理int类型的数值,除此之外还有DoubleStreamLongStream,它们分别处理doublelong类型的数值,只要调用mapToDoublemapToLong方法即可获得对应的数值流,使用方法也是IntStream大同小异,这里就不做详细介绍了。


构建流:

之前的文章中我们一直都是直接调用集合的stream方法来获取一个流,其实获取流的方式有很多种。

  1. 直接使用值初始化流

    public static void valueStream(){
        Stream<String> stream = Stream.of("Hello", "World ");
        stream.map(String::toUpperCase).forEach(System.out::println);
    }
  2. 使用Arrays.stream()静态方法创建流,这个方法接受一个数组

    public  static void arrayStream(){
        String[] strs = new String[]{"Hello","World"};
        Arrays.stream(strs).map(String::toUpperCase).forEach(System.out::println);
    }
  3. 从文件中读取获取流,每一行就是流中的一个元素

    public static void fileStream(){
        try {
            Stream<String> text = Files.lines(Paths.get("C:\\Users\\Half\\Desktop\\test.txt"),Charset.defaultCharset());
            text.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  4. 用函数生成无限流,分别调用Stream.iterate()Stream.generate()方法即可,两者不同之处在于Stream.iterate()方法没生成一个值都要依赖于前一个值,适合生成连续的数值,而Stream.generate()则每个值都是独立生成的,相互之间没有关联。要注意的是因为是无限流,所以会一直生成元素,所以必须要调用limit()方法来限制生成的个数,否则代码会一直运行下。

    • Stream.iterate()接受两个参数,分别是起始值和后续值的生成代码,例如下面这个方法就是从0开始,依次加10

      public static void iterateStream(){
          Stream.iterate(0, num -> num+10).limit(5).forEach(System.out::println);
      }

      运行结果:

      0
      10
      20
      30
      40
    • Stream.generate()接受一个参数,生成数值的代码

      public static void generateStream(){
          Stream.generate(Math::random).limit(5).forEach(System.out::println);
      }

      运行结果:

      0.9538068193407456
      0.5113995186169759
      0.20525086606957266
      0.2974528805300197
      0.019653649898021208

总结:

这篇文章介绍了数值流和构建流的方式,流的应用可以很灵活,后续还会介绍流的用法。


Half
238 声望17 粉丝

The Long Way Round.