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

原创 2018年04月17日 14:49:44

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





版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Daybreak1209/article/details/79972286

Java8基础视频教程

-
  • 1970年01月01日 08:00

Java8 新特性之流式数据处理

一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现。比如我们希望对一个包含整数的...
  • Leolu007
  • Leolu007
  • 2016-12-02 17:37:05
  • 4128

Java8 Stream 流中的匹配查找方法

findAny:查找任何一个就返回 Optional findFirst:查找到第一个就返回 Optional anyMatch:匹配上任何一个则返回 Boolean allMatch:匹配所有...
  • dalinsi
  • dalinsi
  • 2017-09-29 17:37:02
  • 428

java8——流

背景自从lambda表达式成为Java语言的一部分之后,Java集合(Collections)API就面临着大幅变化。而 JSR 355(规定了 Java lambda 表达式的标准)的正式启用更是使...
  • wujiaqi0921
  • wujiaqi0921
  • 2018-03-01 23:40:22
  • 23

Java 8系列之Stream的基本语法详解

概述继Java 8系列之Lambda表达式之后,我们来了解Stream。Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8中的众多新特性之一的聚合操作,开发者可以更容易...
  • IO_Field
  • IO_Field
  • 2017-02-10 16:27:52
  • 16772

【Java8】Java8体验(二)Stream语法详解

转自:http://blog.csdn.net/youzhouliu/article/details/51820076 1. Stream初体验 我们先来看看Java里面是怎么定义Stream的...
  • ljyljyok
  • ljyljyok
  • 2017-09-22 18:50:02
  • 135

Find Q

Find Q    Accepts: 392    Submissions: 780  Time Limit: 2000/1000 MS (Java/Others)    Memor...
  • amazingcode
  • amazingcode
  • 2016-10-05 16:08:37
  • 513

Java 8 数据流Stream的基本使用

数据流(Stream)的基本概念 1. 数据流(Stream)        流 是Java SE 8类库中新增的关键抽象,它被定义于 java.util.stream (这个包里有若干流类型...
  • Al_assad
  • Al_assad
  • 2017-03-06 17:48:09
  • 841

Java8 Stream API

Java8 Stream API Stream是啥 创建流 创建一个空的流 通过集合创建 通过数组创建 直接创建 通过builder创建 generate()和iterate() 合并多个Stre...
  • CL_YD
  • CL_YD
  • 2018-02-25 21:13:39
  • 43

java8实战四:使用流--Stream

使用流在本章中,你将会看到许多Stream API支持的许多操作.这些操作能让你快速完成许多复杂的查询.如筛选、切片、映射、查找、匹配和归约。 接下来,我们会看到一些特殊的流:数值流,来自文件和数组...
  • itguangit
  • itguangit
  • 2017-11-24 14:18:45
  • 246
收藏助手
不良信息举报
您举报文章:java8 流及lamdba应用及性能测试Case
举报原因:
原因补充:

(最多只允许输入30个字)