Java8新特性-Stream API(二)

Java8 Stream API

定义

流是JavaAPI的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。就现在来说,你可以把它们看成遍历数据集合的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码了

与传统写法的优势

  • 声明性——更简洁,更易读
  • 可复合——更灵活
  • 可并行——性能更好

演示代码:
public class StreamDemo1 {

public static void main(String[] args) {

List<Dish> menu = Arrays.asList(
new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 300, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH) );

//传统的编码方式:需要三次,因为必须筛选出菜,才能排序,然后才能得到符合条件排好序的菜的名称列表
//第一个方法,筛选出卡路里低于400的菜
List<Dish> lowCaloricDishes = new ArrayList<>();
for (Dish d : menu) {
if (d.getCalories() < 400) {
lowCaloricDishes.add(d);
}
}

//第二个方法,根据卡路里排序
Collections.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());
}
for(String name: lowCaloricDishesName){
System.out.println("name");
}

System.out.println("---------------------");

//Stream API实现,只需要下指令,比如先过滤排序获取姓名,组成新的数组返回
List<String> streamRes =
menu.stream()
.filter(d -> d.getCalories() < 400)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
streamRes.stream().forEach(System.out::println);

//如果你需要并行处理,只需要在生成流的时候使用并行流parallelStream
    List<String> streamRes =
            menu.parallelStream()
                    .filter(d -> d.getCalories() < 400)
                    .sorted(Comparator.comparing(Dish::getCalories))
                    .map(Dish::getName)
                    .collect(toList());
    streamRes.stream().forEach(System.out::println);
//season fruit,prawns,rice
}
}

流的特性

  • 只能处理一次;请注意,和迭代器类似,流只能迭代一次。处理完之后,我们就说这个流已经被消费掉了流,不能再次使用
  • 内部迭代;内部已经做好了优化,方便并行的方式处理,减少了外部迭代时并行处理时面对的问题

流操作

  • 中间操作。依然返回一个流,达到流水线的处理方式
  • 中断操作。返回的结果不是流,
    操作 filter 过滤
    map 提取
    reduce 归约 组合
    find 查询
    match 匹配
    sort 排序
    distinct 判断原则根据元素的hashcode和equals方法
    skip 跳过元素

一些中间操作的代码示例:

public class StreamDemo {

public static void main(String[] args) {
    List<Dish> menu = Arrays.asList(
            new Dish("pork", false, 800, Dish.Type.MEAT),
            new Dish("beef", false, 700, Dish.Type.MEAT),
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER),
            new Dish("rice", true, 350, Dish.Type.OTHER),
            new Dish("season fruit", true, 120, Dish.Type.OTHER),
            new Dish("pizza", true, 550, Dish.Type.OTHER),
            new Dish("prawns", false, 300, Dish.Type.FISH),
            new Dish("salmon", false, 450, Dish.Type.FISH));

    //第一个需求:找出卡路里高于300的菜品的名字
    List<String> s = menu.stream().filter(d -> d.getCalories() > 300)
            .sorted((s1, s2) -> s1.getCalories() - s2.getCalories())
            .sorted(comparing(Dish::getCalories))
            .map(Dish::getName)// == Function<Dish , String> f2 = (a)->a.getName(); .map(f2)
            .limit(3)
            .collect(toList());

    //allMatch用法,判断是不是都大于100卡路里
    boolean a = menu.stream().allMatch(aa -> aa.getCalories() > 100);
    System.out.println(a);


    //find test
    menu.stream().filter(d -> d.getCalories() > 30000)
            .findAny()
            .ifPresent(d -> System.out.println(d.getName()));

    //find first
    List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
    Optional<Integer> firstSquareDivisibleByThree = someNumbers.stream()
            .map(x -> x * x)
            .filter(x -> x % 3 == 0)
            .findFirst();// 9

    if (firstSquareDivisibleByThree.isPresent()) {
        int value = firstSquareDivisibleByThree.get();
        System.out.println(value);
    }
    //也可以在流处理中直接处理optional
    someNumbers.stream()
            .map(x -> x * x)
            .filter(x -> x % 3 == 0)
            .findFirst().ifPresent(System.out::println);// 9


    //reduce的使用  计算总卡路里值
    //由于没有reduce方法设置默认值,所以为了防止空结果,返回optional
    menu.stream().map(Dish::getCalories).reduce((e1, e2) -> e1 + e2).ifPresent(System.out::println);
    //利用方法引用,Integer类现在有了一个静态的sum方法来对两个数求和
    menu.stream().map(Dish::getCalories).reduce(Integer::sum).ifPresent(System.out::println);
    //rudecu方法传入默认值,则返回结果而不是optional
    int sum = menu.stream().map(Dish::getCalories).reduce(100,Integer::sum);

    //先用map构建数值流,在求和  这种方式避免了Integer::sum的装箱操作
    int total = menu.stream().mapToInt(Dish::getCalories).sum();
    //求最大值max/最小值min方法
    int total2 = menu.stream().mapToInt(Dish::getCalories).max().orElse(1);
    menu.stream().map(Dish::getCalories).reduce(Integer::max).ifPresent(System.out::println);
    menu.stream().map(Dish::getCalories).reduce(Integer::min).ifPresent(System.out::println);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值