java8 流及lamdba应用及性能测试Case

java8闪亮新特性函数式编程-lambda表达式及stream流操作。废话不多说,关键在应用。

一、引入流

1、背景:集合高频使用,API虽丰富,但步骤略繁琐

2、流优势:

1)声明性方式处理数据集合,直达目的,说明想要完成什么,而非利用循环if如何实现一个操作。

2)可组合操作,流水线调用(filter、sorted、map、collect)灵活应对多变需求;行为参数化,根据菜品type、价格、热量筛选即可,而不用复制粘贴代码

3)可并行

3、流组成(input--操作处理--output)

public class Stream1Difine {
    /**
     * 1、源:menu (集合、数组或IO资源)
     * 2、数据处理操作(filter、map、reduce、find、match、sort等;类似于数据库的操作
     * 3、元素序列 threeHighCaloricDishNames (计算结果,仍为集合)
     * 重要2特点
     * 1、流水线 (执行filter、map、reduce等操作返回值为stream-中间操作;执行count、collect返回集合-终端操作)
     * 2、内部迭代 VS 外部迭代(集合)
     */
    @Test
    public void test(){
        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> threeHighCaloricDishNames =
                menu.stream()    //从menu源中获得流
                        .filter(d -> d.getCalories() > 300)  //操作 链路流水线相连
                        .map(Dish::getName) //操作
                        .limit(3) //操作
                        .collect(toList()); //终端操作 将stream转化成另一种形式,开始执行中间操作,返回元素序列

        System.out.println(threeHighCaloricDishNames);
    }
}
其中操作分为中间操作和终端操作。中间操作后返回流,n个中间操作形成流水线,直至终端操作被调用;终端操作将流转为集合输出。常用的中间操作有:filter、map、limit、sorted、distinct,利用流延迟、短路(limit、matchAny、findAny)特性,可根据需求选择调用恰当API,提高系统性能;常用的终端操作有:forEach、count、collect

二、流与集合

集合:如同DVD光盘,所有数据先load到容器中(内存数据结构,先装满,在开始操作);通过外部迭代for循环获取元素。

流:视频流,需要时才会计算出需要的值(需求驱动,实时制造);只能被消费一次,处理完后(执行终端操作后,关闭流),从数据源再获得新的流重新操作;内部循环获取元素。

public class Stream2Collection {
    //只能消费1次
    @Test
    public void test(){
        List<String> title = Arrays.asList("Java8", "In", "Action");
        Stream<String> s = title.stream();
        s.forEach(System.out::println);
        s.forEach(System.out::println);//IllegalStateException: stream has already been operated upon or closed
    }

    //外部迭代与内部迭代
    public void test7(){
       //menu同上
        //外部迭代
        List<String> names = new ArrayList<>();
        Iterator<Dish> iterator = menu.iterator();
        while(iterator.hasNext()) {
            Dish d = iterator.next();
            names.add(d.getName());
        }

        //内部迭代
        List<String> names2 = menu.stream()
                .map(Dish::getName)
                .collect(toList());
    }
}

三、使用流

public class Stream3Operation {
    /**
     * 1、中间操作:连接流  filter、map和limit可以连成一条流水线;  【filter、map、limit、sorted、distinct】
     * 2、终端操作:关闭流  collect触发流水线执行并关闭它           【forEach、count、collect】
     * 只当终端操作触发时,中间操作才开始执行
     */
    @Test
    public void test(){
        List<String> names = menu.stream()
                .filter(d ->{
                    System.out.println("filtering:" + JSON.toJSONString(d));
                    return d.getCalories() > 300;
                })
                .map(d -> {
                    System.out.println("mapping:"  + JSON.toJSONString(d));
                    return d.getName();
                })
                .limit(3)
                .collect(toList());
        System.out.println(JSON.toJSONString(names));
    }

    //使用流
    /**
     * 1、一个数据源(如集合)来执行一个查询
     * 2、一个中间操作链,形成一条流的流水线
     * 3、一个终端操作执行流水线并能生成
     */

    /**
     * 1、筛选
     */
    @Test
    public void testLimit(){
        List<Integer> numbers=Arrays.asList(1,4,6,7,8,6,66,44,3);
        //1、distinct
        numbers.stream()
                .filter(i -> i % 2==0)
                .distinct()
                .forEach(System.out::println);

        //2、截短流 limit
        System.out.println(
                numbers.stream()
                        .filter(i -> i > 4)
                        .limit(2)  //短路 有2就返回了,有false直接返回 profile
                        .collect(toList())
        );
        //3、调过元素 skip
        System.out.println(
                numbers.stream()
                        .filter(i -> i> 33)
                        .skip(1)
                        .collect(toList())
        );
    }

    /**
     * 2、映射 :将传入元素映射成一个新的元素(创建而非修改)
     */
    @Test
    public void testMap(){
        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));

        System.out.println(
                menu.stream()
                        .map(Dish::getName)
                        .collect(toList())
        );
        //多重映射 每道菜名长度
        System.out.println(
                 menu.stream()
                        .map(Dish::getName)
                        .map(String::length)
                        .collect(toList())
        );
    }

    /**
     * 3、查找匹配 allMatch、anyMatch、noneMatch、findFirst、findAny--短路
     */
    @Test
    public void testMacth(){
        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) );

        //1、anyMatch
        if(menu.stream().anyMatch(Dish::isVegetarian)){
            System.out.println("The menu is vegetarian friendly!!");
        }

        //2、allMatch
        System.out.println(menu.stream().allMatch(d -> d.getCalories() < 700));

        //3、noneMatch
        boolean isHealthy = menu.stream()
                .noneMatch(d -> d.getCalories() >= 1000);
        System.out.println(isHealthy);

        //4、findAny
        Optional<Dish> dish =
                menu.stream()
                        .filter(Dish::isVegetarian)
                        .findAny();
        System.out.println("findAny:"+JSON.toJSONString(dish));
    }

四、集合流处理对比

public class CollectMenuUtil {
    public static void getLowCaloricDishesJava7(List<Dish> menu){
        List<Dish> lowCaloricDishes = new ArrayList<>();
        //筛选目标元素
        for(Dish d: menu){
            if(d.getCalories() < 400){
                lowCaloricDishes.add(d);
            }
        }

        // version 1 使用匿名类对菜肴进行排序
        Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
            public int compare(Dish d1, Dish d2){
                return Integer.compare(d1.getCalories(), d2.getCalories());
            }
        });
//        // version 2
//        Collections.sort(lowCaloricDishes, (d1, d2) -> Integer.compare(d1.getCalories(), d2.getCalories()));
//        // version 3
//        Collections.sort(lowCaloricDishes, Comparator.comparingInt(Dish::getCalories));

        //输出得到排序后菜名列表
        List<String> lowCaloricDishesName = new ArrayList<>();
        for(Dish d: lowCaloricDishes){
            lowCaloricDishesName.add(d.getName());
        }
    }


    public static void getLowCaloricDishesJava8(List<Dish> menu){
        List<String> lowCaloricDishesName =
                menu.stream()
                        .filter(d -> d.getCalories() < 400)
                        .sorted(comparing(Dish::getCalories))
                        .map(Dish::getName)
                        .collect(toList());
    }

    public  static  void  getLowCaloricDishesJava8Parallel(List<Dish> menu){
        List<String> lowCaloricDishesName =
                menu.parallelStream()
                        .filter(d -> d.getCalories() < 400)
                        .sorted(comparing(Dish::getCalories))
                        .map(Dish::getName)
                        .collect(toList());
    }

    @Test
    public void test7() {
        long currentTimeMillis = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            CollectMenuUtil.getLowCaloricDishesJava7(Dish.getMenu());
        }
        long java7CostTime = System.currentTimeMillis() - currentTimeMillis;
        System.out.println("java7:" + java7CostTime);//java7:50453

    }

    @Test
    public  void test8(){
        long now = System.currentTimeMillis();
        for (int i=0;i<100000000;i++){
            CollectMenuUtil.getLowCaloricDishesJava8(Dish.getMenu());
        }
        long java8CostTime=System.currentTimeMillis()-now;
        System.out.println("java8:"+java8CostTime);//java8:664
    }

    @Test
    public  void test8Parallel(){
        long now = System.currentTimeMillis();
        for (int i=0;i<100000000;i++){
            CollectMenuUtil.getLowCaloricDishesJava8Parallel(Dish.getMenu());
        }
        long java8CostTime=System.currentTimeMillis()-now;
        System.out.println("java8 parallel:"+java8CostTime);//
    }
}

五、集总

public class TradePractice {
    @Test
    public void test(){
        Trader raoul = new Trader("Raoul", "Cambridge");
        Trader mario = new Trader("Mario","Milan");
        Trader alan = new Trader("Alan","Cambridge");
        Trader brian = new Trader("Brian","Cambridge");
        List<Transaction> transactions = Arrays.asList(
                new Transaction(brian, 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)
        );

//        (1) 找出2011年发生的所有交易,并按交易额排序(从低到高)
        transactions.stream()
                .filter(transaction -> transaction.getYear()==2011)
                .sorted(Comparator.comparing(Transaction::getValue))
                .collect(toList());

//        (2) 交易员都在哪些不同的城市工作过
        transactions.stream()
                .map(transaction -> transaction.getTrader().getCity())
                .distinct()//
                .forEach(System.out::println);

//        或
        transactions.stream()
                .map(transaction -> transaction.getTrader().getCity())
                .collect(toSet());

//        (3) 查找所有来自于剑桥的交易员,并按姓名排序
        transactions.stream()
                .map(Transaction::getTrader) //先拿到trader,再排序
                .filter(trader -> trader.getCity().equals("Cambridge"))
                .sorted(Comparator.comparing(Trader::getName))
                .collect(toSet());


        String traderStr =
                transactions.stream()
                        .map(transaction -> transaction.getTrader().getName())
                        .distinct()
                        .sorted()
                        .reduce("", (n1, n2) -> n1 + n2);


//        (4) 返回所有交易员的姓名字符串,按字母顺序排序
        transactions.stream()
                    .map(Transaction::getTrader)
                    .sorted(Comparator.comparing(trader -> trader.getName()))
                    .collect(toSet());

//        (5) 有没有交易员是在米兰工作的
        transactions.stream()
                    .filter(transaction -> transaction.getTrader().getCity().equals("Milan"))
                    .findAny();

        boolean milanBased =
                transactions.stream()
                        .anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan"));

//        (6) 打印生活在剑桥的交易员的所有交易额
        transactions.stream()
                    .filter(transaction -> transaction.getTrader().getCity().equals("Cambridge"))
                    .map(transaction -> transaction.getValue())
                    .forEach(System.out::println);

//        (7) 所有交易中,最高的交易额是多少
        transactions.stream()
                    .sorted(Comparator.comparing(transaction -> transaction.getValue()))
                    .limit(1)
                    .collect(toList());

        Optional<Integer> highestValue =
                transactions.stream()
                        .map(Transaction::getValue)
                        .reduce(Integer::max);

//        (8) 找到交易额最小的交易
        Optional<Transaction> smallestTransaction =
                transactions.stream()
                        .reduce((t1, t2) ->
                                t1.getValue() < t2.getValue() ? t1 : t2);
    }
}





猜你喜欢

转载自blog.csdn.net/daybreak1209/article/details/79972286