美文网首页程序员Java
Stream API(一)流

Stream API(一)流

作者: LeaveStyle | 来源:发表于2020-04-08 15:57 被阅读0次

流是“从支持数据处理操作的源生成的一系列元素”。流中的元素是按需计算的。

集合的弊端:
1. 无法像SQL语句那样筛选数据,需要利用迭代器或者累加器筛选。
2. 并行处理集合比较繁琐,易出错。

流的优势:
3. 以声明性方式处理数据集合。
4. 透明地进行并行处理,无需写多线程代码。

一、流与集合

代码例子:

//传统集合处理方式
List<Dish> lowCaloricDishes = new ArrayList<>();
//筛选低卡路
for(Dish d : menu){
    if(d.getCalories() < 400){
        lowCaloricDishes.add(d);
    }
}
//按卡路里排序
Collectioins.sort(lowCaloricDishes, new Comparator<Dish>(){
    public int compare(Dish d1, Dish d2){
        return Integer.compare(d1.getCalories(), d2.getCalories());
    }
});
//获取名字集合
List<String> lowCaloricDishesName = new ArrayList<>();
for(Dish d : lowCaloricDishes){
    lowCaloricDishesName.add(d.getName());
}

//流处理方式
List<String> lowCaloricDishesName = menu.stream()
    .filter(d -> d.getCalories() < 400)
    .sort(comparing(Dish::getCalories))
    .map(Dish::getName)
    .collect(toList());
//其中stream可以换成parallelStream来使用并行处理

集合的处理方式一般为外部迭代,而流处理为内部迭代。


内部迭代与外部迭代

二、流操作

流的操作有两类:中间操作和中端操作。
中间操作:输入类型为Stream<T>,输出类型为Stream<T>。
终端操作:输入类型为Stream<T>,输出类型为非Stream值。


中间操作
终端操作

三、使用流

  1. 筛选和切片:filter、distinct、limit、skip
  2. 映射:map、flatMap
  3. 查找和匹配:allMatch、anyMatch、noneMatch、findFirst、findAny
  4. 归约:reduce
    1. 累加:stream().reduce(0, (a, b) -> a + b)
    2. 累乘:stream().reduce(1, (a, b) -> a * b)
    3. 最大值:stream().reduce(Integer::max)
    4. 最小值:stream().reduce(Integer::min)
    5. Lambda替换累加:stream().reduce(0, Integer::sum)
    6. Lambda替换最小值:stream.reduce((x, y) -> x < y ? x : y)

经典案例(交易员和交易问题):

(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。
(2) 交易员都在哪些不同的城市工作过?
(3) 查找所有来自于剑桥的交易员,并按姓名排序。
(4) 返回所有交易员的姓名字符串,按字母顺序排序。
(5) 有没有交易员是在米兰工作的?
(6) 打印生活在剑桥的交易员的所有交易额。
(7) 所有交易中,最高的交易额是多少?
(8) 找到交易额最小的交易。

//Trader类
public class Trader {
    private final String name;
    private final String city;

    public Trader(String name, String city) {
        this.name = name;
        this.city = city;
    }

    public String getName() {
        return name;
    }

    public String getCity() {
        return city;
    }

    @Override
    public String toString() {
        return "Trader{" +
                "name='" + name + " in " +
                "city='" + city  +
                '}';
    }
}

//Transaction类
public class Transaction {
    private final Trader trader;
    private final int year;
    private final int value;

    public Transaction(Trader trader, int year, int value) {
        this.trader = trader;
        this.year = year;
        this.value = value;
    }

    public Trader getTrader() {
        return trader;
    }

    public int getYear() {
        return year;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Transaction{" +
                "trader=" + trader +
                ", year=" + year +
                ", value=" + value +
                '}';
    }
}

//数据
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brain = new Trader("Brain", "Cambridge");

List<Transaction> transactions = Arrays.asList(
    new Transaction(brain, 2011, 300),
    new Transaction(raoul, 2012, 1000),
    new Transaction(raoul, 2011, 400),
    new Transaction(mario, 2012, 710),
    new Transaction(mario, 2012, 700),
    new Transaction(alan, 2012, 950)
);

答案请参考: Steam流--交易员和交易问题答案

四、数值流

Stream API提供了原始类型流特化以支持处理数值流的方法。
Java8引入三个原始类型特化流接口:IntStream、DoubleStream、LongStream,分别将流中的元素特化为 int、double、long,从而避免装箱的成本。

  1. 映射到数值流
    常用方法有mapToInt、mapToDouble、mapToLong,返回的是特化流而不是Stream<T>。
//下面例子中返回的是IntStream,而不是Stream<Integer>
int calories = menu.stream()
                   .mapToInt(Dish::getCalories)
                   .sum();
//sum方法中若流为空,则结果为0。
//IntStream还支持其他方法,如max、min、average等操作。
  1. 数值流转换为对象流
//将 Stream 转 换为数值流
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
//将数值流转 换为Stream
Stream<Integer> stream = intStream.boxed();
  1. 默认值OptionalInt
    Optional类是一个可以表示值存在或不存在的容器。避免了流为空是,数值为0的情况。
    Optional原始类型特化版本:OptionalInt、OptionalDouble、OptionalLong。
// 例如,要找到IntStream中的最大元素,可以调用max方法,它会返回一个OptionalInt:
OptionalInt maxCalories = menu.stream()
                              .mapToInt(Dish::getCalories)
                              .max(); 
// 现在,如果没有最大值的话,你就可以显式处理OptionalInt去定义一个默认值了:
//如果没有最大值的话,显式提供一个默认最大值
int max = maxCalories.orElse(1);
  1. 数值范围
    Java 8引入了两个可以用于IntStream和LongStream的静态方法,range和rangeClosed。这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但 range是不包含结束值的,而rangeClosed则包含结束值。
//表示范围:[1, 100], 一个从1到100的偶数流
IntStream evenNumbers = IntStream.rangeClosed(1, 100) 
                                     .filter(n -> n % 2 == 0);
//结果为50,若改为range方法则结果为49。                                    
System.out.println(evenNumbers.count());

五、构建流

  1. 由值创建流

    //Stream.of创建显示流
    Stream<String> stream = Stream.of("Java 8", "Lambdas ", "in ", "Action");
    //empty得到空流
    Stream<String> emptyStream = Stream.empty();
    
  2. 由数组创建流

    //Arrays.stream从数组创建一个流
    int[] numbers = {2, 3, 5, 7, 11, 13};
    int sum = Arrays.stream(numbers).sum();
    
  3. 由文件生成流
    例如统计一个文件中有多少各不相同的词:


    相关代码介绍
  4. 由函数生成流
    Stream API提供了从函数生成流的方式:Stream.iterate和Stream.generate,这两个操作可以创建无限流(即不像从集合中创建固定大小的流)。

    //依次在每个新产生的值上应用Lambda
    Stream.iterate(0, n -> n + 2)
            .limit(10)
            .forEach(System.out::println);
               
    //这个不是依次对每个新生成的值应用函数
    Stream.generate(Math::random)
            .limit(5)
            .forEach(System.out::println);
    

相关文章

  • jdk8 Stream流

    jdk8 Stream流 1.Stream API 简介 Stream API是Java 8中加入的一套新的API...

  • JDK8-Stream

    Stream概述 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行...

  • Stream API(一)流

    流是“从支持数据处理操作的源生成的一系列元素”。流中的元素是按需计算的。 一、流与集合 代码例子: 集合的处理方式...

  • Stream API

    1. Stream API 简介 Stream API是 JDK8 的新特性,这种风格将要处理的元素集合看作一种流...

  • Stream

    使用 Stream API 高逼格 优化 Java 代码 Java8 Stream流中的 collect() 别再...

  • node之stream - 流

    流(stream)是Nodejs中出处理流式数据的抽象接口。stream模块提供了一些API,用于构建实现了流接口...

  • Java 8 Stream API学习总结

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream API可...

  • Java8 Stream-API

    Java8 Stream-API Stream 流类似集合类中的Iterator,但是比Iterator高级,只需...

  • 深度掌握 Java Stream 流操作,瞬间让你的代码高出一个

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:...

  • 深度掌握 Java Stream 流操作,瞬间让你的代码高出一个

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:...

网友评论

    本文标题:Stream API(一)流

    本文链接:https://www.haomeiwen.com/subject/dnvtmhtx.html