重学java8新特性|第8讲——趁热打铁,快来练练这三道有关streamapi的练习题

李阿昀      2022-04-24     644

关键词:

在上一讲中,我们学了那么的Stream API,是不是应该要用一下啊,不然学它干嘛,所以,本讲我们就趁热打铁赶紧来用一下学过的Stream API,看你会不会用学过的Stream API来解决下面这三道练习题。

练习题一

题目是这样的:给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?即给定[1, 2, 3, 4, 5],应该返回[1, 4, 9, 16, 25]

这道练习题解决起来还是蛮简单的,关键是要用一下map方法,相信大家应该都知道这点,下面我直接给出代码清单。

package com.meimeixia.exer;

import org.junit.Test;

import java.util.Arrays;

/**
 * @author liayun
 * @create 2022-02-12 23:26
 */
public class TestStreamAPI 

    @Test
    public void test1() 
    	Integer[] nums = new Integer[]1, 2, 3, 4, 5;

        Arrays.stream(nums)
                .map((x) -> x * x)
                .forEach(System.out::println);
    


练习题二

题目是这样的:怎样用map和reduce这俩方法数一数流中有多少个元素(例如Employee)呢?

其实,要想数一数流中有多少个元素,很多种方式都可以来解决,但是这道题明确规定了我们只能使用map和reduce这俩方法来解决,所以我们就只能顺从了。

package com.meimeixia.exer;

import com.meimeixia.java8.Employee;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author liayun
 * @create 2022-02-16 18:57
 */
public class TestStreamAPI1 

    List<Employee> employees = Arrays.asList(
            new Employee(100, "张三", 18, 9999.99, Employee.Status.FREE),
            new Employee(101, "李四", 38, 5555.99, Employee.Status.BUSY),
            new Employee(102, "王五", 50, 6666.66, Employee.Status.VOCATION),
            new Employee(103, "赵六", 16, 3333.33, Employee.Status.FREE),
            new Employee(103, "赵六", 16, 3333.33, Employee.Status.FREE),
            new Employee(103, "赵六", 16, 3333.33, Employee.Status.FREE),
            new Employee(104, "田七", 8, 7777.77, Employee.Status.BUSY)
    );

    @Test
    public void test() 
        Optional<Integer> count = employees.stream()
                .map((e) -> 1)
                .reduce(Integer::sum); // 这是根据方法引用的第二种格式(即类::静态方法名)来书写成这样的哟!
        System.out.println(count.get());
    


注意,以上Employee实体类的代码,大家可以参考上一讲中的Employee实体类来写。

练习题三

题目是这样的:有如下三个类,它们分别是,

  • 交易员类:

    package com.meimeixia.exer;
    
    /**
    * 交易员类
    * @author liayun
    * @create 2022-02-16 19:17
    */
    public class Trader 
    
        private String name;
        private String city;
    
        public Trader() 
            super();
            // TODO Auto-generated constructor stub
        
    
        public Trader(String name, String city) 
            super();
            this.name = name;
            this.city = city;
        
    
        public String getName() 
            return name;
        
    
        public void setName(String name) 
            this.name = name;
        
    
        public String getCity() 
            return city;
        
    
        public void setCity(String city) 
            this.city = city;
        
    
        @Override
        public String toString() 
            return "Trader [name=" + name + ", city=" + city + "]";
        
    
    
    
  • 交易类:

    package com.meimeixia.exer;
    
    /**
    * 交易类
    * @author liayun
    * @create 2022-02-16 19:18
    */
    public class Transaction 
    
        private Trader trader;
        private int year;
        private int value;
    
        public Transaction() 
            super();
            // TODO Auto-generated constructor stub
        
    
        public Transaction(Trader trader, int year, int value) 
            super();
            this.trader = trader;
            this.year = year;
            this.value = value;
        
    
        public Trader getTrader() 
            return trader;
        
    
        public void setTrader(Trader trader) 
            this.trader = trader;
        
    
        public int getYear() 
            return year;
        
    
        public void setYear(int year) 
            this.year = year;
        
    
        public int getValue() 
            return value;
        
    
        public void setValue(int value) 
            this.value = value;
        
    
        @Override
        public String toString() 
            return "Transaction [trader=" + trader + ", year=" + year + ", value=" + value + "]";
        
    
    
    
  • 单元测试类:

    package com.meimeixia.exer;
    
    import org.junit.Before;
    
    import java.util.Arrays;
    import java.util.List;
    
    /**
    * @author liayun
    * @create 2022-02-16 19:19
    */
    public class TestTransaction 
    
        List<Transaction> transactions = null;
    
        @Before
        public void before() 
            Trader raoul = new Trader("Raoul", "Cambridge");
            Trader mario = new Trader("Mario", "Milan");
            Trader alan = new Trader("Alan", "Cambridge");
            Trader brian = new Trader("Brain", "Cambridge");
    
            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年发生的所有交易,并按交易额排序(从低到高)。
    
        //2. 交易员都在哪些不同的城市工作过?
    
        //3. 查找所有来自剑桥的交易员,并按姓名排序。
    
        //4. 返回所有交易员的姓名字符串,并按字母顺序排序。
    
        //5. 有没有交易员是在米兰工作的?
    
        //6. 打印生活在剑桥的交易员的所有交易额。
    
        //7. 所有交易中,最高的交易额是多少。
    
        //8. 找到交易额最小的交易。
    
    
    

请你解决如下8个问题。

  1. 找出2011年发生的所有交易,并按交易额排序(从低到高)。
  2. 交易员都在哪些不同的城市工作过?
  3. 查找所有来自剑桥的交易员,并按姓名排序。
  4. 返回所有交易员的姓名字符串,并按字母顺序排序。
  5. 有没有交易员是在米兰工作的?
  6. 打印生活在剑桥的交易员的所有交易额。
  7. 所有交易中,最高的交易额是多少。
  8. 找到交易额最小的交易。

先来看第一个小问题,如果想要找出2011年发生的所有交易,并按交易额排序(从低到高),那么该怎么办呢?这题还是很简单的,下面我直接给出代码清单,不会的童鞋可以参考一下。

//1. 找出2011年发生的所有交易,并按交易额排序(从低到高)。
@Test
public void test1() 
    transactions.stream()
            .filter((t) -> t.getYear() == 2011)
            .sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
            .forEach(System.out::println);

再来看第二个小问题,如果想要找出交易员都在哪些不同的城市工作过,那么是不是就应该像下面这样做啊!

//2. 交易员都在哪些不同的城市工作过?
@Test
public void test2() 
    transactions.stream()
            .map((t) -> t.getTrader().getCity())
            .distinct() // 去重
            .forEach(System.out::println);

再来看第三个小问题,如果想要查找出所有来自剑桥的交易员,并按姓名排序,那么是不是就应该像下面这样做啊!

//3. 查找所有来自剑桥的交易员,并按姓名排序。
@Test
public void test3() 
    transactions.stream()
            .filter((t) -> t.getTrader().getCity().equals("Cambridge"))
            .map(Transaction::getTrader)
            .sorted((t1, t2) -> t1.getName().compareTo(t2.getName()))
            .distinct()
            .forEach(System.out::println);

再来看第四个小问题,这个问题稍微的有那么点争议,就看你是从什么角度去理解这个问题了,下面我会从各种角度出发来解决该问题。

可能大家第一时间想到的代码是下面这样的。

//4. 返回所有交易员的姓名字符串,并按字母顺序排序。
@Test
public void test4() 
    transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .forEach(System.out::println);

右键运行以上test4方法,你确实是可以在控制台中看到按字母顺序排序的所有交易员的姓名,如下图所示。

但是,有童鞋可能不是像上面那样理解的,他理解的是先把所有的交易员的姓名按照字母顺序进行排序,然后再连成一个字符串,即先排后拼。

//4. 返回所有交易员的姓名字符串,并按字母顺序排序。
@Test
public void test4() 
    transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .forEach(System.out::println);

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

    // 但是,有童鞋可能不是像上面那样理解的,他理解的是先把所有的交易员的姓名按照字母顺序进行排序,然后再连成一个字符串,即先排后拼。
    String str = transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .reduce("", String::concat);// 先排后拼。注意,这是根据方法引用的第三种格式(即类::实例方法名)来书写成String::concat这样的哟!
    System.out.println(str);

右键运行以上test4方法,你便可以在控制台中看到先排后拼的所有交易员的姓名了。

当然,也有的童鞋是这样理解的:先将姓名字符串里面的一个一个字符给提取出来,然后再拼成一个字符串,接着按照字母顺序来进行排序,即先拼后排。如果真是这样理解的话,那么代码就应该像下面这样写了。

//4. 返回所有交易员的姓名字符串,并按字母顺序排序。
@Test
public void test4() 
    transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .forEach(System.out::println);

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

    // 但是,有童鞋可能不是像上面那样理解的,他理解的是先把所有的交易员的姓名按照字母顺序进行排序,然后再连成一个字符串,即先排后拼。
    String str = transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .reduce("", String::concat);// 先排后拼。注意,这是根据方法引用的第三种格式(即类::实例方法名)来书写成String::concat这样的哟!
    System.out.println(str);

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

    // 也有的童鞋是这样理解的:先将姓名字符串里面的一个一个字符给提取出来,然后再拼成一个字符串,接着按照字母顺序来进行排序,即先拼后排。
    transactions.stream()
            .map((t) -> t.getTrader().getName())
            .flatMap(TestTransaction::filterCharacter) // 将姓名字符串里面的一个一个字符给提取出来,并变成一个个字符串
            .sorted()
            .forEach(System.out::print);

其中,filterCharacter方法的代码如下所示。

public static Stream<String> filterCharacter(String str) 
    List<String> list = new ArrayList<String>();
    for (Character ch : str.toCharArray()) 
        list.add(ch.toString());
    
    return list.stream();

右键运行以上test4方法,你便可以在控制台中看到这样一串字符串了。

从上面可以清楚地看到,虽然是按照字母顺序来进行排序了,但是排的并不好,因为字母有大小写。实际上,字符在按照字母顺序进行排序时,底层是按照ASCII码来排的,即大写字母在前,小写字母在后。

这时,如果我们想忽略字母大小写来进行排序,那么又该怎么办呢?很简单,像下面这样做就行了!

//4. 返回所有交易员的姓名字符串,并按字母顺序排序。
@Test
public void test4() 
    transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .forEach(System.out::println);

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

    // 但是,有童鞋可能不是像上面那样理解的,他理解的是先把所有的交易员的姓名按照字母顺序进行排序,然后再连成一个字符串,即先排后拼。
    String str = transactions.stream()
            .map((t) -> t.getTrader().getName())
            .sorted()
            .reduce("", String::concat);// 先排后拼。注意,这是根据方法引用的第三种格式(即类::实例方法名)来书写成String::concat这样的哟!
    System.out.println(str);

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

    // 也有的童鞋是这样理解的:先将姓名字符串里面的一个一个字符给提取出来,然后再拼成一个字符串,接着按照字母顺序来进行排序,即先拼后排。
    transactions.stream()
            .map((t) -> t查看详情  

重学java8新特性|第2讲——java8新特性简介(代码片段)

请再看我一眼写在前面你能从这套课程中学到什么呢?Java8有哪些优点?速度更快更新了底层的数据结构Java8对于HashMap所做的改动Java8对于ConcurrentHashMap所做的改动更新了底层的内存结构代码更少(增加了新的语法࿰... 查看详情

重学java8新特性|第1讲——我们为什么要学习java8新特性?(代码片段)

大家好,我是你们的李阿昀,时隔多日,我又重新来更文了,只不过这次我更新的是有关Java8新特性的文章,至于原因是什么,下面我会告诉大家。原因一大家应该知道我正在更新「SpringBoot2从入门到入坟... 查看详情

重学java8新特性|第5讲——函数式接口(代码片段)

我们都知道Lambda表达式需要接口的支持,并且接口中的抽象方法还不能多,只能有一个,不然就没法区分它实现的到底是哪个抽象方法了。一般,我们会称该接口为函数式接口,在上一讲中我就已经提到过了&#... 查看详情

重学java8新特性|第3讲——我们为什么要使用lambda表达式?

接下来,我们就正式来开始学习Java8了。上一讲中,我就已经讲过了,Java8新特性中最为核心的便是Lambda表达式与StreamAPI,只不过这一讲我首先会为大家讲解Lambda表达式。其实,Lambda表达式就是Java8提出的一种... 查看详情

重学java8新特性|第3讲——我们为什么要使用lambda表达式?(代码片段)

接下来,我们就正式来开始学习Java8了。上一讲中,我就已经讲过了,Java8新特性中最为核心的便是Lambda表达式与StreamAPI,只不过这一讲我首先会为大家讲解Lambda表达式。其实,Lambda表达式就是Java8提出的一种... 查看详情

重学java8新特性|第2讲——java8新特性简介

写在前面从本讲开始,咱们就要开始正式学习Java8新特性了,不知大家做好准备没有?做好准备之后,我就要开始发车了。在这一讲中,我会对大家接下来要学习的Java8新特性做一个整体的介绍,以便让大... 查看详情

重学java8新特性|第4讲——lambda表达式详解(代码片段)

文章目录Lambda表达式是什么?Lambda表达式的基础语法语法格式一:无参数,且无返回值语法格式二:有一个参数,并且无返回值语法格式三:若只有一个参数,参数的小括号可以省略不写语法格式四... 查看详情

重学java8新特性|第6讲——方法引用与构造器引用(代码片段)

我们为什么要使用方法引用与构造器引用呢?如果不使用Lambda表达式进行程序编写的话,那么大可不必关注方法引用和构造器引用,但是如果使用Lambda表达式,再配合方法引用和构造器引用之后,那么就可以... 查看详情

重学java8新特性|第3讲——我们为什么要使用lambda表达式?(代码片段)

接下来,我们就正式来开始学习Java8了。上一讲中,我就已经讲过了,Java8新特性中最为核心的便是Lambda表达式与StreamAPI,只不过这一讲我首先会为大家讲解Lambda表达式。其实,Lambda表达式就是Java8提出的一种... 查看详情

重学java8新特性|第1讲——我们为什么要学习java8新特性?(代码片段)

大家好,我是你们的李阿昀,时隔多日,我又重新来更文了,只不过这次我更新的是有关Java8新特性的文章,至于原因是什么,下面我会告诉大家。原因一大家应该知道我正在更新「SpringBoot2从入门到入坟... 查看详情

java8新特性及实战视频教程完整版

第1讲:课程介绍第2讲:课程介绍续第3讲:Lambda表达式初步与函数式接口第4讲:深入函数式接口与方法引用第5讲:Lambda表达式深入与流初步第6讲:Function接口详解第7讲:Function与BiFunction函数式接口详解第8讲:BiFunction函数式接... 查看详情

重学java8新特性|第4讲——lambda表达式详解(代码片段)

在详细讲解Lambda表达式之前,我们先看一下Lambda表达式的概述,即Lambda表达式是什么?Lambda表达式是什么?Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进... 查看详情

重学java8新特性|第6讲——方法引用与构造器引用(代码片段)

我们为什么要使用方法引用与构造器引用呢?如果不使用Lambda表达式进行程序编写的话,那么大可不必关注方法引用和构造器引用,但是如果使用Lambda表达式,再配合方法引用和构造器引用之后,那么就可以... 查看详情

第8讲——函数探幽

...知识,但需要学习的知识还很多。C++还提供许多新的函数特性,使之有别于C语言。新特性包括内联函数、按引用传递变量、默认的参数值、函数重载(多态)以及模板函数。这一讲中,我们将介绍C++在C语言基础上新增的 查看详情

整理java8新特性总结(代码片段)

闲语:  相比于今年三月份才发布的Java10,发布已久的Java 8已经算是老版本了(传闻Java11将于9月25日发布....)。然而很多报道表明:Java9和JJava10不是LTS版本,和过去的Java大版本升级不同,它们只有半年左右的开发和维护... 查看详情

java8十大新特性详解(代码片段)

前言: Java 8已经发布很久了,很多报道表明Java 8是一次重大的版本升级。在JavaCodeGeeks上已经有很多介绍Java8新特性的文章,例如PlayingwithJava8–LambdasandConcurrency、Java8DateTimeAPITutorial:LocalDateTime和AbstractClassVersusInterfacein 查看详情

java8主要新特性----------------jdk1.8优点概括

...加了新的语法Lambda表达式)     增加新特性Lambda表达式的内部类改造,使得代码在书写上变得更加简 查看详情