JDK8新特性:lambda表达式,方法引用,Stream流以及Stream流相关的三套练习题

1、Lambda表达式规范

1、lambda表达式
  规则:
    语法结构:()->{}
    参数列表:类型可以省略,单参数时可以省略()
    箭头符合分割参数和主体
    主体部分:单行表达式可以省略{}和return;多行语句需要完整编写
    简化匿名内部类的编写和函数式接口的使用

代码案例:

        System.out.println("lambda表达式");
        System.out.println("--1、无参数无返回值----");
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("  ");
            }
        };
        r1.run();
        Runnable r2 = () -> System.out.println("lambda表达式");
        r2.run();
        System.out.println("2、需要一个参数,但是没有返回值");
        Consumer<Object> c1 = new Consumer<>() {
            @Override
            public void accept(Object o) {
                System.out.println(" ");
            }
        };
        Consumer c2 = s -> System.out.println("一个参数");

        System.out.println("3、形参类型不管---省略");
        System.out.println("4、一个参数可不写小括号==省略");
        System.out.println("5、两个或两个以上参数,多条执行语句,并且可以有返回值");
        Comparator<Integer> c3 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(c3.compare(2, 1));
        Comparator<Integer> c4 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(c4.compare(1, 2));
        System.out.println("6、lamb体只有一条语句时,return与大括号若有,都可省略。第一个已有");

2、方法引用

        方法引用 格式:使用方法引用操作符“::”将类(或对象)与方法名分隔开来。
      – 两个:中间不能有空格,而且必须英文状态下半角输入
        三种情况
        – 情况1:对象::实例方法名 – 情况2:类::静态方法名 – 情况3:类::实例方法名
        使用前提:要求1:Lambda体只有一句语句,并且是通过调用一个对象的/类现有的方法
来完成的 例如:System.out对象,调用println()方法来完成Lambda体  Math类,调用random()静态方法来完成Lambda体
        要求2:
针对情况1:函数式接口中的抽象方法a在被重写时使用了某一个对象的方法 b。如果方法a的形参列表、返回值类型与方法b的形参列表、返回值类型都相同,则我们可以使用方法b实现对方法a的重写、替换。
针对情况2:函数式接口中的抽象方法a在被重写时使用了某一个类的静态方法b。如果方法a的形参列表、返回值类型与方法b的形参列表、返回值类型都相同,则我们可以使用方法b实现对方法a的重写、替换。
针对情况3:函数式接口中的抽象方法a在被重写时使用了某一个对象的方法 b。如果方法a的返回值类型与方法b的返回值类型相同,同时方法a的形参列表中有n个参数,方法b的形参列表有n-1个参数,且方法a的第1个参数作为方法b的调用者,且方法a的后n-1参数与方法b的n-1参数匹配(类型
相同或满足多态场景也可以)

代码案例:

//        情况1、对象::实例方法
        //Consumer中的void accept(T t) //PrintStream中的void println(T t)
        Consumer<String> c5 = s -> System.out.println(s);
        c5.accept("lambda");
        PrintStream ps = System.out;
        Consumer<String> c6 = ps::println;
        c6.accept("对象/实例方法");

        //Supplier中的T get() Employee中的String getName()
        Employee emp = new Employee(1001, "Tom", 23, 5600);
        Supplier<String> s1 = () -> emp.getName();
        System.out.println(s1.get());

        Supplier<Object> supplier = new Supplier<>() {
            @Override
            public Object get() {
                return null;
            }
        };

        Supplier<String> s2 = emp::getName;
        System.out.println(s2.get());

//        情况2:类::静态方法
        //Comparator中的int compare(T t1,T t2)  Integer中的int compare(T t1,T t2)
        Comparator<Integer> h1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        };
        Comparator<Integer> c7 = (x1, x2) -> Integer.compare(x1, x2);
        System.out.println(c7.compare(1, 2));

        Comparator<Integer> c8 = Integer::compare;
        System.out.println(c8.compare(2, 1));

        //情况三:类::实例方法 (有难度)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
        String s = "12";
        s.compareTo("21");
//        public int compareTo(String anotherString) {
//            byte v1[] = value;
//            byte v2[] = anotherString.value;
//            byte coder = coder();
//            if (coder == anotherString.coder()) {
//                return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
//                        : StringUTF16.compareTo(v1, v2);
//            }
//            return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
//                    : StringUTF16.compareToLatin1(v1, v2);
//        }

        Comparator<String> com1 = (s3, s4) -> s3.compareTo(s4);
        Comparator<String> d2 = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        };

        System.out.println(com1.compare("abc", "abd"));
        System.out.println("*******************");
        Comparator<String> com2 = String::compareTo;
        //        第一个参数作为方法的调用者 见d2
        System.out.println(com2.compare("abd", "abm"));

        System.out.println("构造器引用");
//        当Lambda表达式是创建一个对象,并且满足Lambda表达式形参,正好是给创建这个对象的构造器的实参列表,就可以使用构造器引用。
//        构造器引用
//        格式:类名::new
//Supplier中的T get()
//Employee的空参构造器:Employee()
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println("*******************");
        Supplier<Employee> sup1 = () -> new Employee();
        System.out.println(sup1.get());
        System.out.println("*******************");
        Supplier<Employee> sup2 = Employee::new;
        System.out.println(sup2.get());

        Function<Integer, Employee> func1 = id -> new Employee(id);
        Employee employee = func1.apply(1001);
        System.out.println(employee);
        System.out.println("*******************");
        Function<Integer, Employee> func2 = Employee::new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);

3、Stream流

1、创建流,省略
2. 中间操作
2.1删选和切片
Stream<T> filter(Predicate<? super T> predicate);接受一个lambda,从流中过滤出需要的元素
  distinct() 通过流所生成元素的hashcode()和equals()去重
  limit(long maxSize) 截断流,使其元素不超过给定数量maxSize
  skip(long n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补

        2.2 映射转换 映射是对最终的结果进行映射,也就是最后的元素类型会变成映射的元素类型
        map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应到每个元素上,产生一个新的DoubleStream
        mapToInt(ToIntFunction f)  产生一个新的IntStream
        mapToLong(ToLongFunction f) 产生一个新的LongStream
        flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
        2.3 排序
        sorted 产生一个新流,其中按自然元素排序
        sorted(Comparator com)  产生一个新流,其中按照比较器顺序排序

        3 终止操作,只能终止一次,一次过后不能再重新使用
        3.1 匹配与查找
        allMatch(Predicate p) 检查是否匹配所有元素
        anyMatch(Predicate p) 检查是否存在一个符合条件的元素
        noneMatch(Predicate p) 检查是否没有匹配所有元素
        findFirst() 返回第一个元素
        findAny() 返回当前的流中的任意元素
        count()   返回流中元素总数
        max(Comparator c) 返回流中的最大值
        min(Comparator c) 返回流中的最小值
        forEach(Consumer c) 内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。<br>相反, Stream API使用内部迭代——它帮你把迭代做了)

        3.2 归约
        reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回T
        reduce(BinaryOperator b)  可以将流中元素反复结合起来,得到一个值。返回Optional
        3.3 收集
        collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
        Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、 Set、Map)。
       另外, Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下:
        toList Collector<T, ?, List> 把流中元素收集到List、
        toSet Collector<T, ?, Set> 把流中元素收集到Set
        toCollection Collector<T, ?, C> 把流中元素收集到创建的集合
        counting Collector<T, ?, Long> 计算流中元素的个数
        summingInt Collector<T, ?, Integer> 对流中元素的整数属性求和
        averagingInt Collector<T, ?, Double> 计算流中元素Integer属性的平均值
        summarizingInt Collector<T, ?,IntSummaryStatistics>  收集流中Integer属性的统计值。
        joining Collector<CharSequence, ?, String> 连接流中每个字符串
        maxBy Collector<T, ?, Optional> 根据比较器选择最大值
        minBy Collector<T, ?, Optional> 根据比较器选择最小值
        reducing Collector<T, ?,Optional> 从一个作为累加器的初始值开始,利用BinaryOperator与流中
        元素逐个结合,从而归约成单个值
        collectingAndThen Collector<T,A,RR> 包裹另一个收集器,对其结果转换函数
        groupingBy Collector<T, ?, Map<K,List>> 根据某属性值对流分组,属性为K,结果为V
        partitioningBy Collector<T, ?, Map<Boolean,List>> 根据true或false进行分区

代码案例:

//        1、创建流,省略
//        2. 中间操作
//        2.1删选和切片
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
//      Stream<T> filter(Predicate<? super T> predicate);接受一个lambda,从流中过滤出需要的元素
//        distinct() 通过流所生成元素的hashcode()和equals()去重
//        limit(long maxSize) 截断流,使其元素不超过给定数量maxSize
//        skip(long n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
//        Predicate是函数式接口,抽象方法:boolean test(T t)
        stream.filter(x -> x / 2 != 0);
        Stream.of(1, 2, 3, 4, 5, 6, 2, 2, 3, 3, 4, 4, 5)
                .distinct().limit(3).filter(x -> x / 1 != 0)
                .forEach(System.out::println);
        //希望能够找出前三个最大值,前三名最大的,不重复
        Stream.of(11, 2, 39, 4, 54, 6, 2, 22, 3, 3, 4, 54, 54)
                .distinct()
                .sorted((t1, t2) -> -Integer.compare(t1, t2))//Comparator接口 int compare(T t1, T t2)
                .limit(3)
                .forEach(System.out::println);
//        2.2 映射转换
//        map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
//        mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应到每个元素上,产生一个新的DoubleStream
//        mapToInt(ToIntFunction f)  产生一个新的IntStream
//        mapToLong(ToLongFunction f) 产生一个新的LongStream
//        flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
//        2.3 排序
//        sorted 产生一个新流,其中按自然元素排序
//        sorted(Comparator com)  产生一个新流,其中按照比较器顺序排序
        //Function<T,R>接口抽象方法R apply(T t)
        System.out.println("--------map----------");
        Stream.of(1, 2, 3, 4, 5).map(x -> x + 1).forEach(System.out::println);
        String[] arr = {"hello", "world", "java"};
        Arrays.stream(arr)
                .map(t -> t.toUpperCase())
                .forEach(System.out::println);
        Arrays.stream(arr)
                .flatMap(t -> Stream.of(t.split("|")))
                //Function<T,R> 接口抽象方法R apply(T t) 现在的R是一个Stream
                .forEach(System.out::println);
//        3 终止操作,只能终止一次,一次过后不能再重新使用
//        3.1 匹配与查找
//        allMatch(Predicate p) 检查是否匹配所有元素
//        anyMatch(Predicate p) 检查是否存在一个符合条件的元素
//        noneMatch(Predicate p) 检查是否没有匹配所有元素
//        findFirst() 返回第一个元素
//        findAny() 返回当前的流中的任意元素
//        count()   返回流中元素总数
//        max(Comparator c) 返回流中的最大值
//        min(Comparator c) 返回流中的最小值
//        forEach(Consumer c) 内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。<br>相反,
//        Stream API使用内部迭代——它帮你把迭代做了)
        boolean b2 = Stream.of(1, 2, 3, 4, 5, 6).allMatch(x -> x / 1 != 0);
        boolean b1 = Stream.of(1, 2, 3).anyMatch(x -> x / 2 == 1);
        boolean b = Stream.of(1, 2, 3).noneMatch(x -> x > 5);
        Optional<Integer> first = Stream.of(1, 2, 3).findFirst();
        System.out.println(first);
        Optional<Integer> max = Stream.of(1, 2, 3).max(Integer::compareTo);
        Optional<Integer> max1 = Stream.of(1, 2, 3).max((x1,x2)->x1.compareTo(x2));
        System.out.println(max);
//        3.2 归约
//        reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回T
//        reduce(BinaryOperator b)  可以将流中元素反复结合起来,得到一个值。返回Optional
//        3.3 收集
//        collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
//        Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、 Set、Map)。
//       另外, Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下:
//        toList Collector<T, ?, List> 把流中元素收集到List、
//        toSet Collector<T, ?, Set> 把流中元素收集到Set
//        toCollection Collector<T, ?, C> 把流中元素收集到创建的集合
//        counting Collector<T, ?, Long> 计算流中元素的个数
//        summingInt Collector<T, ?, Integer> 对流中元素的整数属性求和
//        averagingInt Collector<T, ?, Double> 计算流中元素Integer属性的平均值
//        summarizingInt Collector<T, ?,IntSummaryStatistics>  收集流中Integer属性的统计值。
//        joining Collector<CharSequence, ?, String> 连接流中每个字符串
//        maxBy Collector<T, ?, Optional> 根据比较器选择最大值
//        minBy Collector<T, ?, Optional> 根据比较器选择最小值
//        reducing Collector<T, ?,Optional> 从一个作为累加器的初始值开始,利用BinaryOperator与流中
//        元素逐个结合,从而归约成单个值
//        collectingAndThen Collector<T,A,RR> 包裹另一个收集器,对其结果转换函数
//        groupingBy Collector<T, ?, Map<K,List>> 根据某属性值对流分组,属性为K,结果为V
//        partitioningBy Collector<T, ?, Map<Boolean,List>> 根据true或false进行分区

//          toList Collector<T, ?, List> 把流中元素收集到List、
        ArrayList<Employee> list = new ArrayList<>();
        List<Employee> emps= list.stream().collect(Collectors.toList());
//        toSet Collector<T, ?, Set> 把流中元素收集到Set
        Set<Employee> emp2= list.stream().collect(Collectors.toSet());
//        toCollection Collector<T, ?, C> 把流中元素收集到创建的集合
        Collection<Employee> emp3 =list.stream().collect(Collectors.toCollection(ArrayList::new));
//        counting Collector<T, ?, Long> 计算流中元素的个数
        long count = list.stream().collect(Collectors.counting());
//        summingInt Collector<T, ?, Integer> 对流中元素的整数属性求和
        int total=list.stream().collect(Collectors.summingInt(Employee::getAge));
//        averagingInt Collector<T, ?, Double> 计算流中元素Integer属性的平均值
        double avg = list.stream().collect(Collectors.averagingInt(Employee::getAge));
//        summarizingInt Collector<T, ?,IntSummaryStatistics>  收集流中Integer属性的统 计值。如:平均值
        IntSummaryStatistics SummaryStatisticsiss= list.stream()
                .collect(Collectors.summarizingInt(Employee::getAge));
//        joining Collector<CharSequence, ?, String> 连接流中每个字符串
        String str= list.stream().map(x->x.getName()).collect(Collectors.joining());
        String a1= list.stream().map(Employee::getName).collect(Collectors.joining());
//        maxBy Collector<T, ?, Optional> 根据比较器选择最大值
        Optional<Employee>max2= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getAge)));
        Optional<Employee>max3= list.stream().max(comparingInt(Employee::getAge));
//        minBy Collector<T, ?, Optional> 根据比较器选择最小值
        Optional<Employee> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getAge)));
        Optional<Employee> min2 = list.stream().min(comparingInt(Employee::getAge));
//        reducing Collector<T, ?,Optional> 从一个作为累加器的初始值开始,利用BinaryOperator与流中
//        元素逐个结合,从而归约成单个值
        Double total2=list.stream().collect(Collectors.reducing(0.0, Employee::getSalary, Double::sum));
        Double total3= list.stream().map(Employee::getSalary).reduce(0.0, Double::sum);
//        collectingAndThen Collector<T,A,RR> 包裹另一个收集器,对其结果转换函数
        int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
//        groupingBy Collector<T, ?, Map<K,List>> 根据某属性值对流分组,属性为K,结果为V
        Map<String, List<Employee>> w1 = list.stream().collect(Collectors.groupingBy(emp1 -> emp1.getName()));
        Map<String, List<Employee>> w2 = list.stream().collect(Collectors.groupingBy(Employee::getName));
//        partitioningBy Collector<T, ?, Map<Boolean,List>> 根据true或false进行分区
        Map<Boolean, List<Employee>> w4 = list.stream().collect(Collectors.partitioningBy(x -> x.getStatus()));
        Map<Boolean, List<Employee>> w3 = list.stream().collect(Collectors.partitioningBy(Employee::getStatus));

4、第一套和第二套练习题(代码写在一起的)以及相关的实体类

@ToString
public class Order {
    private String orderId;
    private String customerName;
    private double amount;
    private String status; // PAID, UNPAID, CANCELLED

    public Order(String orderId, String customerName, double amount, String status) {
        this.orderId = orderId;
        this.customerName = customerName;
        this.amount = amount;
        this.status = status;
    }

    // Getters
    public String getOrderId() { return orderId; }
    public String getCustomerName() { return customerName; }
    public double getAmount() { return amount; }
    public String getStatus() { return status; }
}

class OrderProduct {
    private String orderId;
    private List<Product> products;

    public OrderProduct(String orderId, List<Product> products) {
        this.orderId = orderId;
        this.products = products;
    }

    public String getOrderId() {
        return orderId;
    }

    public List<Product> getProducts() {
        return products;
    }
}

class Product {
    private String name;
    private double price;
    private int quantity;

    public Product(String name, double price, int quantity) {
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public int getQuantity() {
        return quantity;
    }
}



@ToString
public class Student {
    private String name;
    private int age;
    private double score;
    private String className; // 班级名称

    public Student(String name, int age, double score, String className) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.className = className;
    }

    // Getters
    public String getName() { return name; }
    public int getAge() { return age; }
    public double getScore() { return score; }
    public String getClassName() { return className; }
}

        List<Student> students = Arrays.asList(
                new Student("Alice", 18, 85.5, "ClassA"),
                new Student("Bob", 19, 92.0, "ClassB"),
                new Student("Charlie", 20, 78.0, "ClassA"),
                new Student("David", 18, 92.0, "ClassB")
        );
        List<Order> orders = Arrays.asList(
                new Order("O1", "Alice", 1000.0, "PAID"),
                new Order("O2", "Bob", 1500.0, "PAID"),
                new Order("O3", "Charlie", 500.0, "UNPAID"),
                new Order("O4", "David", 2000.0, "CANCELLED")
        );
//        1、从 students 中筛选出 年龄≥18岁且分数≥80 的学生,并收集到列表。
        List<Student> c1 = students.stream().filter(stu -> stu.getAge() >= 18).filter(stu1 -> stu1.getScore() >= 80).toList();
        List<Student> c2 = students.stream().filter(s -> s.getScore() >= 80 && s.getAge() >= 18).toList();
        System.out.println(c1);
        System.out.println(c2);
//        2、提取所有学生的 班级名称,去重后收集到集合。
        Set<String> c3 = students.stream().map(s1 -> s1.getClassName()).distinct().collect(Collectors.toSet());
        Set<String> c4 = students.stream().map(Student::getClassName).collect(Collectors.toSet());
        System.out.println(c3);
        System.out.println(c4);
//        3、将学生按 分数降序 排序,若分数相同则按 年龄升序 排序。
        List<Student> c5 = students.stream().sorted(Comparator.comparingDouble(
                        Student::getScore).reversed().thenComparing(Student::getAge))
                .collect(Collectors.toList());
        System.out.println(c5);
//        4、找出学生中 分数最高 的学生(若多人并列,返回第一个)。
        Optional<Student> c6 = students.stream().max(Comparator.comparingDouble(Student::getScore));
        System.out.println(c6);
//        5、按班级分组,计算每个班级的 平均分数。
        Map<String, Double> c7 = students.stream().collect(Collectors.groupingBy
                (Student::getClassName, Collectors.averagingDouble(Student::getScore)));
        System.out.println(c7);
//        6、统计订单列表中各状态的 订单数量和总金额。
        System.out.println("-----------");
        Map<String, DoubleSummaryStatistics> c8 = orders.stream().collect
                (Collectors.groupingBy(Order::getStatus, Collectors.summarizingDouble(Order::getAmount)));
        System.out.println(c8);

        System.out.println("-----------new Test----------------------");
        List<Product> products = Arrays.asList(
                new Product("Apple", 1.5, 10),
                new Product("Banana", 0.5, 20),
                new Product("Orange", 2.0, 15),
                new Product("Mango", 3.0, 5)
        );
//        7、从products列表中过滤出价格大于 1.0 的产品,并将其 名称 映射到一个新的列表中。
//        过滤出数量大于 10 的产品,计算这些产品的总价格。
        List<Product> q1 = products.stream().filter(x -> x.getPrice() > 1.0).collect(Collectors.toList());
        List<String> r1 = products.stream().filter(product -> product.getPrice() > 1.0)
                .map(product -> product.getName()).collect(Collectors.toList());
        System.out.println(q1);
        System.out.println("r1: " + r1);
        DoubleSummaryStatistics q2 = products.stream().filter(t -> t.getQuantity() > 10)
                .collect(Collectors.summarizingDouble(Product::getPrice));
        System.out.println(q2);
        double r2 = products.stream().filter(x -> x.getQuantity() > 10).mapToDouble(Product::getPrice).sum();
        System.out.println("r2:" + r2);
//        8、1根据产品名称的首字母对产品进行分组,返回一个Map<Character, List<Product>>,
//        其中键是产品名称的首字母,值是对应的产品列表。
//        2、统计不同价格区间的产品数量,价格区间分为 [0, 1)、[1, 2)、[2, +∞)
//        返回一个Map<String, Long>,其中键是价格区间描述,值是该区间的产品数量。TODO
        Map<Character, List<Product>> q3 = products.stream().collect(Collectors.groupingBy
                (product -> product.getName().charAt(0)));
        Map<String, Long> r4 = products.stream().collect(Collectors.groupingBy(product -> {
            if (product.getPrice() < 1) {
                return "[0,1)";
            } else if (product.getPrice() < 2) {
                return "[1,2)";
            } else {
                return "[2,+oo]";
            }
        }, Collectors.counting()));
        System.out.println("r4:" + r4);

//        9、按照产品价格从高到低对产品列表进行排序,返回排序后的产品名称列表。
//          查找价格最高的产品,如果存在则返回其名称,否则返回 "无产品"。
//          查找数量最少的产品,如果存在则返回其名称,否则返回 "无产品"。
        List<String> q5 = products.stream().
//                注意映射放在排序后面,收集前面
        sorted(Comparator.comparingDouble(Product::getPrice).reversed())
                .map(Product::getName).collect(Collectors.toList());
//        Product q6 = products.stream().max(Comparator.comparingDouble(Product::getPrice)).orElse();
        String maxName = products.stream().max(Comparator.comparingDouble(Product::getPrice)).map(Product::getName).orElse("无产品");
        String minName = products.stream().min(Comparator.comparingInt(Product::getQuantity)).map(Product::getName).orElse("无产品");
        System.out.println("maxName:" + maxName + "\nminName:" + minName);

        List<OrderProduct> orderProducts = Arrays.asList(
                new OrderProduct("O1", Arrays.asList(
                        new Product("Apple", 1.5, 10),
                        new Product("Banana", 0.5, 20)
                )),
                new OrderProduct("O2", Arrays.asList(
                        new Product("Orange", 2.0, 15),
                        new Product("Mango", 3.0, 5)
                ))
        );
//        10、将orders列表中的所有产品扁平化到一个列表中,并统计产品的总数量。
//          计算所有订单中产品的总价格。
//          找出所有订单中价格最高的产品,如果存在则返回其名称,否则返回 "无产品"。
        int sum = orderProducts.stream().flatMap(order -> order.getProducts().stream()).mapToInt(Product::getQuantity).sum();
        String s = orderProducts.stream().flatMap(orderProduct -> orderProduct.getProducts().stream()).
                max(Comparator.comparingDouble(Product::getPrice)).map(Product::getName).orElse("无产品");
        System.out.println("总价格为:"+sum+"\n最高产品名称为:"+s);

5、第三套练习题以及相关的实体类和基础数据

public class Order {
    private Long id;
    private List<OrderItem> items;
    private LocalDate orderDate;
    // 状态:CREATED, PAID, COMPLETED
    private String status;
    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", items=" + items +
                ", orderDate=" + orderDate +
                ", status='" + status + '\'' +
                '}';
    }
    public Order(Long id, List<OrderItem> items, LocalDate orderDate, String status) {
        this.id = id;
        this.items = items;
        this.orderDate = orderDate;
        this.status = status;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public LocalDate getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(LocalDate orderDate) {
        this.orderDate = orderDate;
    }

    public List<OrderItem> getItems() {
        return items;
    }

    public void setItems(List<OrderItem> items) {
        this.items = items;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    // 构造方法/getter/setter省略
}


// 订单项类
public class OrderItem {
    private Product product;
    private int quantity;

    @Override
    public String toString() {
        return "OrderItem{" +
                "product=" + product +
                ", quantity=" + quantity +
                '}';
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public OrderItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }
// 构造方法/getter/setter省略
}


// 产品类
public class Product {
    private Long id;
    private String name;
    private double price;
    // 分类:电子、图书、服装等
    private String category;

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", category='" + category + '\'' +
                '}';
    }

    public Product(Long id, String name, double price, String category) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.category = category;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }
    // 构造方法/getter/setter省略
}

public class StreamTest {
    static List<Product> products = Arrays.asList(
            new Product(1L, "iPhone 13", 5999.0, "电子"),
            new Product(2L, "Java编程思想", 99.0, "图书"),
            new Product(3L, "男士衬衫", 199.0, "服装"),
            new Product(4L, "MacBook Pro", 12999.0, "电子"),
            new Product(5L, "Python入门", 59.0, "图书")
    );

    static List<Order> orders = Arrays.asList(
            new Order(1L, Arrays.asList(
                    new OrderItem(products.get(0), 1),
                    new OrderItem(products.get(1), 2)
            ), LocalDate.of(2023, 3, 15), "PAID"),

            new Order(2L, Arrays.asList(
                    new OrderItem(products.get(3), 1),
                    new OrderItem(products.get(4), 3)
            ), LocalDate.of(2023, 3, 16), "COMPLETED"),

            new Order(3L, Arrays.asList(
                    new OrderItem(products.get(2), 2),
                    new OrderItem(products.get(4), 1)
            ), LocalDate.of(2023, 3, 17), "CREATED")
    );

    public static void main(String[] args) {
//        1、过滤 找出所有价格超过100元的电子产品
        List<Product> t1 = products.stream().
                filter(product -> product.getPrice() > 100 && "电子".equals(product.getCategory()))
                .collect(Collectors.toList());
//        2、映射 提取出所有的订单Id集合
        List<Long> t2 = orders.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<Long> t22 = orders.stream().map(Order::getId).toList();
//        3、排序 按价格降序排列所有图书类商品
        List<Product> t3 = products.stream().filter(p -> "图书".equals(p.getCategory()))
                .sorted(Comparator.comparingDouble(Product::getPrice).reversed()).collect(Collectors.toList());
//        List<Product> t33 = products.stream().filter(p -> "图书".equals(p.getCategory()))
//                排序这里用lambda表达式会报错,只能用方法引用 见上面
//                .sorted(Comparator.comparingDouble(p->p.getPrice()).reversed()).collect(Collectors.toList());
//        4、去重  获取所有出现过的商品分类
        List<String> t4 = products.stream().map(p -> p.getCategory()).distinct().collect(Collectors.toList());
        List<String> t44 = products.stream().map(Product::getCategory).distinct().toList();
//        5、限制与跳过 获取价格排名前三的商品
        List<Product> t5 = products.stream()
                .sorted(Comparator.comparingDouble(Product::getPrice))
                .limit(3).toList();
//        默认是按照升序排列,所以降序要使用 reversed方法
        List<Product> t55 = products.stream()
                .sorted(Comparator.comparingDouble(Product::getPrice).reversed())
                .limit(3).toList();
        System.out.println(t5);
        System.out.println(t55);
//      6、匹配 检查是否有未支付的订单
        boolean t6 = orders.stream().anyMatch(order -> "CREATED".equals(order.getStatus()));
//      7、规约操作 求和 计算所有订单的总金额
        double t7 = orders.stream()
                .flatMap(o -> o.getItems().stream())
                .mapToDouble(item -> item.getProduct()
                        .getPrice() * item.getQuantity())
                .sum();
//        8、最大最小值  找出最贵的商品
        Optional<Product> t8 = products.stream().max(Comparator.comparingDouble(p -> p.getPrice()));
//        收集器
//        9、分组 按订单状态分组统计订单数量
        Map<String, Long> t9 = orders.stream().
                collect(
                        Collectors.groupingBy(o -> o.getStatus(), Collectors.counting())
                );
//        10、连接字符串 将所有商品名称按照逗号连接
        String t10 = products.stream().map(Product::getName)
                .collect(Collectors.joining(","));
//        11、扁平化 获取所有订单中的商品列表(去重)
        List<Product> t11 = orders.stream()
                .flatMap(o -> o.getItems().stream())
                .map(OrderItem::getProduct)
                .distinct().collect(Collectors.toList());
//        12、并行流(parallelStream) 使用并行流计算所有图书类商品的总价格
        double t12 = products.parallelStream()
                .filter(p -> "图书".equals(p.getCategory()))
                .mapToDouble(Product::getPrice).sum();
        System.out.println(t12);
//       复杂多条件过滤 TODO
//        假设我们有一个Product实体类,需要根据以下条件过滤商品:
//        1、价格在100到1000之间
//        2、分类为“电子”或“图书”
//        3、名称包含“Pro”或“入门”
//        实现方法:方法1 直接在filter中写多条件
        List<Product> filteredProducts1 = products.stream()
                .filter(p -> p.getPrice() >= 100 && p.getPrice() <= 1000) // 条件1
                .filter(p -> "电子".equals(p.getCategory()) || "图书".equals(p.getCategory())) // 条件2
                .filter(p -> p.getName().contains("Pro") || p.getName().contains("入门")) // 条件3
                .collect(Collectors.toList());
//        方法2:使用Predicate组合条件
        // 定义多个条件
        Predicate<Product> priceCondition = p -> p.getPrice() >= 100 && p.getPrice() <= 1000;
        Predicate<Product> categoryCondition = p -> "电子".equals(p.getCategory()) || "图书".equals(p.getCategory());
        Predicate<Product> nameCondition = p -> p.getName().contains("Pro") || p.getName().contains("入门");
//          组合条件
        List<Product> filteredProducts2 = products.stream()
                .filter(priceCondition.and(categoryCondition).and(nameCondition))
                .collect(Collectors.toList());
//        方法三:使用自定义方法封装条件
        List<Product> filteredProduct3 = products.stream()
                .filter(new StreamTest()::isProductValid)
                .collect(Collectors.toList());
//        方法4:动态构建条件 如果需要根据外部参数动态构建条件,可以使用Predicate的动态组合
        // 动态条件
        List<Predicate<Product>> conditions = new ArrayList<>();
        conditions.add(p -> p.getPrice() >= 100 && p.getPrice() <= 1000);
        conditions.add(p -> "电子".equals(p.getCategory()) || "图书".equals(p.getCategory()));
        conditions.add(p -> p.getName().contains("Pro") || p.getName().contains("入门"));
// 组合条件
        Predicate<Product> combinedCondition = conditions.stream()
                .reduce(Predicate::and)
                .orElse(p -> true); // 如果没有条件,默认返回 true

        List<Product> filteredProducts4 = products.stream()
                .filter(combinedCondition)
                .collect(Collectors.toList());
        List<Product> products = Arrays.asList(
                new Product(1L, "iPhone 13 Pro", 5999.0, "电子"),
                new Product(2L, "Java编程入门", 99.0, "图书"),
                new Product(3L, "男士衬衫", 199.0, "服装"),
                new Product(4L, "MacBook Pro", 12999.0, "电子"),
                new Product(5L, "Python入门", 59.0, "图书")
        );
        System.out.println("过滤后的商品:");
        filteredProducts4.forEach(p -> System.out.println(p.getName()));
    }

    //  方法3 封装条件到方法
    private boolean isProductValid(Product product) {
        boolean priceValid = product.getPrice() >= 100 && product.getPrice() <= 1000;
        boolean categoryValid = "电子".equals(product.getCategory()) || "图书".equals(product.getCategory());
        boolean nameValid = product.getName().contains("Pro") || product.getName().contains("入门");
        return priceValid && categoryValid && nameValid;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值