java8 lambda stream学习

1. 简介

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yR3VRVlA-1593843611869)(lambda.assets/image-20200704140545686.png)]

接口、匿名内部类可以采用lambda实现 格式 参数列表括号括起来 -> 功能体 stream则让Java能够像sql一样操作集合等数据

lambda需要函数式接口的支持 函数式接口: 接口中只有一个抽象方法的接口 @FunctionalInterface 修饰一下

Lambda 就相当于接口、匿名内部类的简便写法

    @Test 
    public void test1() {
        Comparator<Integer> com0 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
        Comparator<Integer> com2 = Comparator.comparingInt(x -> x);
        Comparator<Integer> com3 = Integer::compare;
      
        List<Employee> employees = filterEmployee(employeeList, e -> e.getSalary() >= 5000);
        employees.forEach(System.out::println);
      
     		employeeList
                .stream()
                .filter(x -> x.getSalary() > 5000)
                .limit(2)
                .forEach(System.out::println);

        employeeList
                .stream()
                .map(Employee::getName)
                .forEach(System.out::println);

      //Collections在lambda中很常用
       @Test
    public void test8() {
        Collections.sort(employeeList, (e1, e2) -> {
            if (e1.getAge() == e2.getAge()) {
                return e1.getName().compareTo(e2.getName());
            } else {
                return Integer.compare(e1.getAge(), e2.getAge());
            }
        });
    }
      
    }

2. 语法格式

  • 格式一: 无参数、无返回值

     Runnable r2=() -> System.out.println("runnable test");
    
  • 格式二: 有一个参数、无返回值(一个参数小括号可以省略)

    Consumer<String> con = (x) -> System.out.println(x); 
    Consumer<String> con = x -> System.out.println(x); 
    Consumer<String> con = System.out::println; //idea 智能生成
    
  • 格式三: 只有一条语句、大括号和return都可以省略不写

     Comparator<Integer> com =(x,y)->{
        return Integer.compare(x,y);
            };
    Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
    
  • 格式四: 参数类型可以省略不写,Java根据上下文可以推断出来 类型推断

3. 四大内置接口

lambda需要函数式接口的支持,有时需要我们自己去创建函数式接口去支持,但Java8已经内置四大函数式接口

1. 消费型接口Consumer<T>

// 消费型接口 无返回值
Consumer<T>:
		void accept(T t); 


  public void consumerInterface(double money, Consumer<Double> con) {
        //具体实现在lambda表达式里面体现
        con.accept(money);
    }
    
    public void test9(){
        consumerInterface(1000,(m)-> System.out.println("consumer"+m));
    }

2. 供给型接口Supplier<T>

Supplier<T>:
	T get()
    
  //产生元素
    public List<Integer> getNumList(int num, Supplier<Integer> sup) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
              //具体实现在lambda表达式里面体现
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }

    @Test
    public void test10() {
        //没有输入参数,所以为空 () ->
        List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 1000));
        for (Integer integer : numList) {
            System.out.println(integer);
        }
    }

3. 函数型接口Function<T,R>

Function<T,R>
  	apply(T)

public void strHandeler(String str, Function<String, String> fun) {
      //具体实现在lambda表达式里面体现
        fun.apply(str);
    }

    @Test
    public void test11() {
//        strHandeler(" a b c d",(str) -> str.trim());
        strHandeler("a b c d", String::trim);

//        strHandeler("a b c d ",str -> str.toUpperCase());
        strHandeler("a b c d", String::toUpperCase);
    }

4. 断言型接口Predicate<T>

Predicate<T>
  	boolean test(T t)
  
  
   public List<String> filterStr(List<String> list, Predicate<String> predicate){
        ArrayList<String> arrayList = new ArrayList<>();

        for (String s : list) {
            //具体实现在lambda表达式里面体现
            if(predicate.test(s)){
                arrayList.add(s);
            }
        }
        return arrayList;
    }

    @Test
    public void test12(){
        List<String> asList = Arrays.asList("hello", "java", "lambda");
        List<String> strings = filterStr(asList, s -> s.length() > 3);
    }

4. 方法引用

若lambda体中的内容已经有方法实现了,那么就可以使用方法引用,方法引用就像下面的,算是lambda的特殊表达方式 xxx::xx

//       strHandeler(" a b c d",(str) -> str.trim());
//      String类已经做好了trim方法,就直接调用String::trim即可
        strHandeler("a b c d", String::trim);

//再比如 直接调用 System.out的方法println
Consumer<String> con = x -> System.out.println(x)
Consumer<String> con = System.out::println 
  
Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Comparator.comparingInt(x -> x);
Comparator<Integer> com3 = Integer::compare;

使用要求: 已实现方法的参数列表、返回值类型必须和使用lambda表达式的参数列表、返回值类型一致才可以

比如:

Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com3 = Integer::compare;

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

Integer.compare 方法接收的参数列表为两个、返回值为int与使用lambda表达式一致

主要有以下三种类型

  • 对象::实例方法名 empList::getName //后面的()都可以省略 getName()
  • 类::静态方法名
  • 类::实例方法名 // 用在(x,y) -> x.equal(y) 等同于 String::equals 接收两个参数 第一个参数为方法调用者,第二个参数为方法参数

5. 构造器引用

格式: ClassName::new 会根据左侧类中方法的参数去自动匹配右侧方法的哪个构造方法

Supplier<Employee> sup = () -> new Employee();

// 会根据左侧类中方法的参数去自动匹配右侧方法的哪个构造方法
// 无参构造器、一参构造器、多参构造器 
Supplier<Employee> sup2 = Employee::new; 

数组引用: Type[]::new

Function<Integer,String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);

Function<Integer,String[]> fun2 = String[]::new;
String[] str2 = fun2.apply(20);

6. Stream

  1. 简介: Stream 能够使数据源(集合、数组等)转换为流然后执行一系列的流水式的中间操作(filter 过滤) 筛选 切片等产生一个新的流,而原来的数据源不会发生任何改变, 类似于sql操作数据 集合是数据,流是计算

  2. 注意点: Stream不会存储元素,不会改变源对象,返回持有结果的心Stream,操作延时,需要等到结果时才执行

  3. 步骤 :创建Stream、中间操作、终止操作

    public class aaa {
    
     List<Employee> employeeList = Arrays.asList(
                new Employee("张三", 18, 9999.99, Employee.Status.FREE),
                new Employee("李四", 25, 789.99, Employee.Status.BUSY),
                new Employee("王武", 12, 2359.99, Employee.Status.BUSY),
                new Employee("赵六", 78, 4569.99, Employee.Status.BUSY),
                new Employee("王二", 34, 956789.99, Employee.Status.VOCATION),
                new Employee("王八", 88, 329.99, Employee.Status.VOCATION),
                new Employee("牛二", 23, 953699.99, Employee.Status.BUSY),
                new Employee("狗蛋", 67, 95654.99, Employee.Status.FREE)
        );
    
        //创建Stream
        @Test
        public void test1() {
            // 1 可以通过Collection系列集合提供的stream() 串行流  或 parallelStream() 并行流
            List<String> list = new ArrayList<>();
            Stream<String> stream1 = list.stream();
    
            // 2 通过Arrays中的静态方法stream() 获得数组流
            Employee[] employees = new Employee[10];
            Stream<Employee> stream2 = Arrays.stream(employees);
    
            // 3 通过stream()类中的静态方法 of()
            Stream<String> stream3 = Stream.of("aa", "bb", "cc");
    
            // 4 创建无限流
            // 迭代
            Stream<Integer> stream4 = Stream.iterate(0, x -> x * 2);
    
            //生成
            Stream<Double> generate = Stream.generate(() -> Math.random());
        }
    
    
        //中间操作
        //不会执行任何的操作,惰性求值
        @Test
        public void test2() {
    
            //过滤 filter
            employeeList.stream()
                    .filter(x -> x.getAge() > 35)
                    .forEach(System.out::println);
    
            employeeList.stream()
                    .filter((e) -> {
                        System.out.println("短路");
                        return e.getAge() > 35;
                    }).forEach(System.out::println);
    
    
            // 截取 limit
            employeeList.stream()
                    .limit(2)
                    .forEach(System.out::println);
    
    
            // 跳过 skip(n) 扔掉前n个,返回后面的元素,如果不满n 则返回空流 与 limit互补
            employeeList.stream()
                    .skip(2)
                    .forEach(System.out::println);
    
    
            // 去重 distinct 通过hashCode 和 equal 去重 需要有hashCode equal方法
            employeeList.stream()
                    .distinct()
                    .forEach(System.out::println);
    
    
            //map 一般 直接 类::方法 class::method
            // 映射 map 接收一个lambda将元素转换成其他形式或提取信息
            // 接收一个函数作为参数,该函数会应用到每个元素上,并将其映射成新的元素
            // scala很简单经常用
            List<String> asList = Arrays.asList("aa", "bb", "cc");
            asList.stream()
    //                .map(l -> l.toUpperCase())
                    .map(String::toUpperCase)
                    .forEach(System.out::println);
            employeeList.stream()
                    .map(Employee::getName)
                    .forEach(System.out::println);
    // flatMap 压平
    
    
            //排序
            employeeList.stream()
    //                .sorted()
                    .sorted((e1, e2) -> {
                        if (e1.getAge().equals(e2.getAge())) {
                            return e1.getName().compareTo(e2.getName());
                        } else {
                            return e1.getAge().compareTo(e2.getAge());
                        }
                    })
                    .forEach(System.out::println);
        }
    
    
        //终止操作
        @Test
        public void termianteed() {
    /**
     * 匹配
     * allMatch-检查是否匹配所有元素 是true 否false
     * anyMatch 检查是否有一个匹配
     * noneMatch 检查是否没有匹配的 false说明至少有一个匹配 true没有一个匹配的 双重否定->肯定
     *
     * 查找
     * findFirst 返回第一个元素
     * findAny  返回当前流中的任意一个
     */
    
            boolean busy = employeeList.stream()
                    .allMatch(e -> e.getStatus().equals("BUSY"));
    
            boolean busy1 = employeeList.stream()
                    .anyMatch(e -> e.getStatus().equals("BUSY"));
    
            boolean busy2 = employeeList.stream()
                    .noneMatch(e -> e.getStatus().equals("BUSY"));
    
    
            Optional<Employee> first = employeeList.stream()
                    .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                    .findFirst();
    
            // option 看来 java的lambda与scala很像啊
    
    //        employeeList.stream()
            employeeList.parallelStream()
                    .filter(e -> e.getStatus().equals("FREE"))
                    .findAny();
    
    
            // count max min
            employeeList.stream()
                    .count();
    
            employeeList.stream()
                    .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
    
            //最少的工资
            employeeList.stream()
                    .map(Employee::getSalary)
                    .min(Double::compare);
    
    
            //归约 reduce 从scala的角度来看,这就很easy了
            Arrays.asList(1, 2, 3, 4, 5).stream()
                    //初始值 操作方法
                    .reduce(0, Integer::sum);
    
            employeeList.stream()
                    .map(Employee::getSalary)
                    .reduce(Double::sum);
    
    
            //收集 collect收集流中的元素
            employeeList.stream()
                    .map(Employee::getName)
    //                .collect(Collectors.toList());
                    .collect(Collectors.toCollection(HashSet::new));
    
            //分组
            employeeList.stream()
                     .collect(Collectors.groupingBy(Employee::getStatus));
    
            employeeList.stream()
                    .map(e->1)
                    .reduce(Integer::sum);
    
        }
    }
    
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章