Stream入门及Stream在JVM中的线程表现

继上次学习过Java8中的非常重要的Lambda表达式之后,接下来就要学习另一个也比较重要的知识啦,也就如标题所示:Stream,而它的学习是完全依赖于之前学习的Lambda表达式。

小实验引入:

这里继续参照java8 in action,关于Stream也是有专门章节去介绍的:

下面就正式开启Stream的学习之旅,这里先做一个实验,用实验来引起Stream,而这实验来源于书中,关于菜方面滴:

所以跟着书本上的来,先建一个菜的实体:

/**
 * 菜实体
 */
public class Dish {

    /* 菜名 */
    private final String name;
    /* 是否是素食 */
    private final boolean vegetarian;
    /* 卡路里 */
    private final int calories;
    /* 菜的类型 */
    private final Type type;

    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }


    public String getName() {
        return name;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public int getCalories() {
        return calories;
    }

    public Type getType() {
        return type;
    }

    public enum Type {MEAT, FISH, OTHER}


    @Override
    public String toString() {
        return "Dish{" +
                "name='" + name + '\'' +
                ", vegetarian=" + vegetarian +
                ", calories=" + calories +
                ", type=" + type +
                '}';
    }
}

然后想从一个菜集合中拿到低于400卡路里的所有菜,并且以卡路里进行排序,而且最终只需要拿到满足条件的菜名,而非菜的实体,所以首先先构建一个集合:

public class SimpleStream {

    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));

    }
}

首先用传统的方式来获取上面条件的菜,比较简单:

public class SimpleStream {

    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));
        List<String> disNamesByCollections = getDishNamesByCollections(menu);
        System.out.println(disNamesByCollections);
    }

    private static List<String> getDishNamesByCollections(List<Dish> menu) {
        List<Dish> lowCalories = new ArrayList<>();

        for (Dish dish : menu) {
            if (dish.getCalories() < 400)
                lowCalories.add(dish);
        }

        Collections.sort(lowCalories, (d1, d2) -> Integer.compare(d1.getCalories(), d2.getCalories()));

        List<String> dishNameList = new ArrayList<>();
        for (Dish lowCalory : lowCalories) {
            dishNameList.add(lowCalory.getName());
        }

        return dishNameList;
    }
}

编译运行:

那如果采用stream方式实现同样的功能,那代码是长啥样呢?首先在集合中会有一个方法将它转成Stream对象,如下:

所以可以这么写代码:

首先去做条件过滤:卡路里<400,其Stream中就有现成过滤的方法:

所以加入过滤条件:

接着对颜色进行排序,那如何整呢?Stream依然有专门排序的方法,继续可以链下去调用:

而据之前学习的方法推导,所以上面排序的代码改用方法推荐如下:

接着从结果集中只取出名字,接着可以调用Stream的这个方法:

最后则返回List,如下:

是不是写法有些怪异,查看一下它的源码:

接着来调用一下用stream实现的方式,但输出是否也能正确:

直观的感受下这两者的实现代码:

什么是stream?

这时再来看下书中对它的介绍:

只是这个细节被隐藏了,关于并行处理,可以看一下Stream的源码:

那如何验证这个stream是并发处理的呢?这里通过jconsole来查看一下线程运行情况。

Stream在JVM中的线程表现

首先先查看一下普通方式在JVM线程中的表现:

运行,然后用jconsole连接上:

接着换成stream方式,将普通方式注掉:

这时运行:

然后用jconsole来连接查看一下当前jvm的线程情况:

呃,貌似跟之前使用普通的方式在JVM中线程一样,那何以知道使用stream方式是以并发的方式呢?这里要想让stream并行处理需要改造一下代码如下:

这时运行再用jconsole来查看就可以感知到啦:

posted on 2017-11-06 22:31  cexo  阅读(598)  评论(0编辑  收藏  举报

导航