java8函数式处理操作一——引入流高效解决集合排序问题

现在我们先来实现一个实体类,这是一个菜肴类,有名字,是否含蔬菜,卡路里含量,类型四个变量,除了get(),set()外还加了一个compareTo()方法,可按照卡路里含量从大到小排列

现在我们用三种方法完成一件事情——从菜肴菜单中从大到小输出卡路里含量大于300的菜肴名字
这是菜肴菜单列表
List mymenu = 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) );

代码

首先我们实现实体类

package stream;

/**
 * @Author 陈松
 * @date 3:01  2019/2/3
 * @modify:
 */
public class Dish {
    private final String name;
    private final boolean vegetarian;
    private final int calories;
    private final Type type;
    public enum Type { MEAT, FISH, OTHER };
    
    public String getName() {
        return name;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public int getCalories() {
        return calories;
    }

    public Type getType() {
        return type;
    }


    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }
    public int compareTo(Dish dish){
        return -(this.getCalories()-dish.getCalories());
    }
}

然后我们建立一个mymenu集合保存大量的Dish,然后要求排序,并选出目标Dish,代码看起来长,但是我通过注释分成了三个方法,结构非常简单
我们要做的事情是从菜肴菜单中从大到小输出卡路里含量大于300的菜肴名字
这是菜肴菜单列表

package stream;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 陈松
 * @date 3:03  2019/2/3
 * @modify: java8使用stream来实现对列表的筛选操作,流只能遍历一次
 */
public class Demo01 {
   
    public static void main(String[] args){
        //集合像DVD,流像在线流媒体
        List<Dish> mymenu = 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) );
        //使用集合的sort方法,调用compareTo()来实现从大到小排序(适用java7的两种方法,流式遍历不需要这个)
        mymenu.sort(Dish::compareTo);

        /**
         * 没有技术含量的循环遍历
         */
        List<String>list=new ArrayList<>();
        for(Dish d:mymenu){
            if(d.getCalories()>300) {
                list.add(d.getName());
            }
        }
        System.out.println(list);

        /**
         * 换汤不换药的迭代器遍历
         */
        List<String>list2=new ArrayList<>();
        Iterator<Dish>iterator=mymenu.iterator();
        while (iterator.hasNext()){
            Dish dish=iterator.next();
            if(dish.getCalories()>300) {
                list2.add(dish.getName());
            }
        }
        System.out.println(list2);

        /**
         * 高端的流式遍历筛选,这段代码独立
         */
        List<String>threeHigh=mymenu.stream()
                .filter(dish -> dish.getCalories()>300)  //过滤器(依赖lambda表达式),只要calories>300的
                .map(Dish::getName)                     //映射要输出的是类的getName
                //.limit(3)                                //限制只要三个   
                .collect(Collectors.toList());           //输出到列表中
        System.out.println(threeHigh);
        
		//我们也可以换个条件继续输出别的,非常灵活
        List<String>threeHigh2=mymenu.stream()
                .filter(Dish::isVegetarian)
                .map(Dish::getName)
                .collect(Collectors.toList());
     
        System.out.println(threeHigh2);
    }
}

这是效果图
java8函数式处理操作一——引入流高效解决集合排序问题

我们再来分析一下这段代码

 List<String>threeHigh=mymenu.stream()
                .filter(dish -> dish.getCalories()>300)  //过滤器(依赖lambda表达式),只要calories>300的
                .map(Dish::getName)                    	 //映射要输出的是类的getName
                //.limit(3)                               			 //限制只要三个   
                .collect(Collectors.toList());          	 //输出到列表中

可以看到我注释掉了limit(3),你可以解除注释看看效果
事实上,这些filter(),map()方法都属于实用的Stream API提供的操作,还有很多其他的,我们可以以后介绍

上面这四个操作中,前三个统称为“中间操作”,因为他们是在同一条“流水线”上,第四关成为“终端操作”,新开另一条流水线
java8函数式处理操作一——引入流高效解决集合排序问题
何为流水线?我们来打印一下具体每一步发生了什么
java8函数式处理操作一——引入流高效解决集合排序问题
可以发现,这四个方法的顺序是
filter()->map()->filter()->map()->filter()->map()->collect()

而limit(3)是在无形中已经起到作用了,而且他直接就返回了目标,而不像前两个方法一样我们需要手动遍历整个列表,这里将遍历方法内置了,这样的最大好处是可以自动选择最优的遍历方法,我们只需要让他遍历,而不需要关心怎么遍历
java8函数式处理操作一——引入流高效解决集合排序问题
所以前三个方法是循环执行的,得到最后结果是才调用第四个方法

以上是流解决集合排序问题的一个简单方法,核心就是那四行代码!其他的都是废话,随便看看就行