Lambda表达式

第一章 练习题

1 练习题一

题一:调用Collections.sort()方法,通过定值排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda作为参数传递

1.1 分析

  • 定制排序:指自定义比较器|定制排序

​ 自然排序:内部比较器|自然排序

  • 先比较年龄,年龄相同才比较姓名

  • 注意: 函数式接口作为形参,lambda表达式作为实参,将行为作为参数传递

1.2 代码

public class Class001_TestLambda {
	public static void main(String[] args) {
		List<Employee> list = Arrays.asList(
				new Employee("bcd",27,9500),
				new Employee("aaa",29,10000),
				new Employee("abc",28,8000),
				new Employee("bc",28,9000)
		);

		System.out.println(list);

		//Collections.sort()
		//Collections.sort(list);
		//sort(List<T> list, Comparator<? super T> c)  将一个list集合,根据指定的规则做升序排序
		Collections.sort(list,(x,y)->{
			if(x.getAge()==y.getAge()){
				return y.getName().compareTo(x.getName());
			}
			return Integer.compare(y.getAge(),x.getAge());
		});

		System.out.println(list);
		
	}
}

2 练习题二

2.1 题目

  • 声明函数式接口,接口中声明抽象方法,public String getValue(String str)

  • 声明类 TestLambda,类中编写方法使用接口作为参数,讲一个字符串转成大写,并作为方法的返回值

  • 再将一个字符串的第2个和第4个索引位置进行截取子串

2.2 代码

public class Class002_TestLambda {
	public static void main(String[] args) {
		System.out.println(strHandler("abcd",s->s.toUpperCase()));
		System.out.println(strHandler("qwertyuiop",s->s.substring(2,5)));
	}

	//功能: 能够对一个字符串,进行某种操作,返回结果
	public static String strHandler(String str,MyFunction my){
		return my.getValue(str);
	}
}

@FunctionalInterface
interface MyFunction{
	public String getValue(String str);
}

3 练习题

3.1 题目

  • 声明一个带两个泛型的函数式接口,发型类型为<T,R> T为参数,R为返回值
  • 接口中声明对应抽象方法
  • 在TestLambda类中声明方法,参数三个,两个long类型的参数,接口作为参数,接口实现中计算两个long型参数的和
  • 再计算两个long型参数的乘积

3.2 代码

public class Class003_TestLambda {
	public static void main(String[] args) {
		System.out.println(testLong(100L,200L,(x,y)->x+y));;
		System.out.println(testLong(100L,200L,(x,y)->x*y));;
	}

	//能够对两个long类型的数据进行某种操作,返回结果
	public static long testLong(Long l1,Long l2,MyFunction2<Long,Long> my){
		return my.test(l1,l2);
	}
}

@FunctionalInterface
interface MyFunction2<T,R>{
	R test(T t1,T t2);
}

4 Employee类

public class Employee implements Comparable<Employee>{
    private String name;
    private int age;
    private double salary;

    public Employee() {
    }

    public Employee(String name) {
        this.name = name;
    }

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }

    @Override
    public int compareTo(Employee o) {
        if(this.age==o.age){
            return this.name.compareTo(o.name);
        }
        return Integer.compare(this.age,o.age);
    }
}

第二章 四大内置函数式接口

1 函数式接口理解

  • 只有一个必须被重写的抽象方法的接口

  • @FunctionalInterface 注解强制检测是否为函数式接口

  • java.util.function 包下提供了一系列的函数式接口

2 四大内置函数式接口

  • Consumer 消费型接口(有来无回)
    • void accept(T t) 对给定的参数执行此操作。
  • Function<T,R> 函数型接口(有一个参数,有一个返回值)
    • R apply(T t) 将此函数应用于给定的参数。
  • Supplier 供给型接口(没参数,有一个返回值)
    • T get() 获取结果。
  • Predicate 段言型接口 (有一个参数进行判定,返回布尔结果)
    • boolean test(T t) 根据给定的参数计算此谓词。

3 代码

public class Class001_FunctionalInterface {
    public static void main(String[] args) {
        testComsumer(5000,m-> System.out.println("为主播打赏"+m));
        testComsumer(10000,m-> System.out.println("今天做全身spa消费"+m));

        System.out.println(strHandler("   哈哈 ",s->s.trim()));
        System.out.println(strHandler("   abc ",s->s.toUpperCase()));

        //[5,10]
        System.out.println(testNumRandom(5,()->(int)(Math.random()*(10-5+1)+5)));
        System.out.println(testNumRandom(10,()->(int)(Math.random()*(20-10+1)+10)));

        System.out.println(testString(List.of("张三","李四","张三丰","欧阳王渊"),s->s.length()>=3));
    }

    //对一个集合中的多个字符串进行某种规则的过滤,返回过滤后的结果
    public static List<String> testString(List<String> list, Predicate<String> pre){
        //定义一个List集合,存储满足条件的字符串
        List<String> strs = new ArrayList<>();
        //遍历原list集合,拿到每一个字符串进行判定
        for(String s :list){
            //满足条件字符串放入strs集合
            if(pre.test(s)){
                strs.add(s);
            }
        }
        return strs;
    }

    //功能: 提供指定个数的,指定规则的随机整数
    //定义方法: 1)需求  2)参数:  不确定的数据|有可能会改变的数据定义参数列表上    3)返回值: 方法执行完毕是否需要得到一个结果,需要定义返回值   4)方法名 : 见名知意
    public static List<Integer> testNumRandom(int num, Supplier<Integer> sup){
        //定义一个List集合,存储生成的随机数
        List<Integer> list = new ArrayList<>();
        //循环num次,每次调用get方法生成一个随机数
        for(int i=1;i<=num;i++){
            list.add(sup.get());
        }
        //返回结果
        return list;
    }

    //功能: 对一个字符串进行某种行为的操作得到结果
    public static String strHandler(String str, Function<String,String> fun){
        return fun.apply(str);
    }

    //功能: 每天的缴费记录
    public static void testComsumer(double money, Consumer<Double> con){
        con.accept(money);
    }
}

第三章 方法引用

1 理解

  • 方法引用 :: (看得懂,能修改)
    • 简化lambda表达式的
    • 是lambda表达式的另外一种变现形式

2 使用前提

  • 当lambda体的实现是通过调用另外一个方法实现的,可以通过方法引用直接引用这个方法,用来简化完整的lambda表达式的结构

3 语法

  • 对象::实例方法
  • 类名::静态方法
  • 类名::实例方法

4 要求

  • 1、lambda体的实现是通过调用另外一个方法实现的

  • 2、lambda的参数列表与返回值要求能够一一对应lambda体中所引用方法的参数列表与返回值

  • 3、lambda的返回值要求与所引用方法的返回值保持对应一致
    lambda的参数列表如果只有一个参数 : 作为调用所引用的成员方法的对象存在
    lambda的参数列表如果存在多个参数 : 第一个参数作为调用所引用的成员方法的对象存在,lambda的第二个参数开始,一一对应匹配所引用方法的参数列表

  • 注意:2和3满足一个就行了

5 构造器引用

  • 数据类型::new

6 代码

public class Class002_MethodQuite {
    public static void main(String[] args) {
        test4();
    }

    //构造器引用
    public static void test4(){
        //1)lambda的参数列表匹配构造器的参数列表,lambda返回值就是所构建的对象--> 构造器引用
        //Supplier<Employee> sup= ()->new Employee();
        Supplier<Employee> sup= Employee::new;
        System.out.println(sup.get());

        //Function<String,Employee> fun = (s)->new Employee(s);
        Function<String,Employee> fun = Employee::new;
        System.out.println(fun.apply("zhangsan"));
    }

    //类名::实例方法
    public static void test3(){
        ///判断 : 1)lambda体的实现是通过调用另外一个方法实现的  ->√ equals  
        //2)lambda的返回值要求与所引用方法的返回值保持对应一致,lambda的参数列表如果存在多个参数 : 第一个参数作为调用成员方法的对象存在,lambda的第二个参数开始,匹配所引用方法的参数列表 ->对
        //BiPredicate<String,String> pre = (x,y) -> x.equals(y);
        BiPredicate<String,String> pre = String::equals;
        System.out.println(pre.test(new String("nihao"),"nihao"));;
    }

    //类名::静态方法
    public static void test2(){
        //Comparator<Integer> com = (x,y) -> x-y;  //不能通过方法引用,因为-是四则运算,不是方法的调用
        //判断 : 1)lambda体的实现是通过调用另外一个方法实现的->√ compare   
        //2)lambda的参数列表与返回值要求能够一一对应lambda体中所引用方法的参数列表与返回值 √
        //Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
        Comparator<Integer> com = Integer::compare;
        System.out.println(com.compare(100,101));;
    }

    //对象::实例方法
    public static void test1(){
        List<Integer> list = List.of(1,2,3,4,5);
        //判断 : 1)lambda体的实现是通过调用另外一个方法实现的->√ println  
        //2)lambda的参数列表与返回值要求能够一一对应lambda体中所引用方法的参数列表与返回值  √
        PrintStream ps = System.out;
        //Consumer con = i -> System.out.println(i);
        //Consumer con = i -> ps.println(i);
        Consumer con = ps::println;

        list.forEach(con);

        list.forEach(ps::println);

        list.forEach(System.out::println);
    }
}

第四章 Stream

1 Stream理解

  • 数据的渠道,用来操作由数据源(数组,集合)所产生的元素序列.
  • IO : 传输数据
  • Stream流 : 操作数据,计算数据
  • 数组|集合 : 存储数据

2 特点

  • Stream流本身不会存储数据
  • Stream不会修改数据源|源对象,每次会返回持有结果的新的流Stream
  • 延迟执行|惰性加载 : 当获取终止行为时候,才会执行一系列的中间操作
  • 流都是一次性的流,不能重复使用多次,一旦使用过就已经被破坏

3 步骤

  • 创建Stream
    • Collection->stream
    • Arrays->stream(数组)
    • Stream.of(值列表)
  • 一系列流式的中间操作(都会返回一个持有结果的新的流)
  • 终止行为

4 代码

  • 创建Stream三种方式的使用
public class Class001_Stream {
    public static void main(String[] args) {
        //Collection-->stream()
        Stream<Integer> stream =  List.of(1,2,3,4,5).stream();
        System.out.println(stream);
        stream.forEach(System.out::println);

        //Arrays->stream(数组)
        String[] arr = {"aaa","bbb","ccc"};
        Stream<String> stream1 = Arrays.stream(arr);
        stream1.forEach(System.out::println);

        //Stream.of(值列表)
        Stream<Integer> stream2 = Stream.of(5,4,3,2,1);
        stream2.forEach(System.out::println);
    }
}

5 中间操作

5.1 方法

  • 过滤 Stream filter(Predicate<? super T> predicate);
  • 去重 distinct()
    比较equals与hashCode()
  • 截取 limit(long) 从第一个开始截取几个
  • 跳过 skip(long) 跳过前n个
  • 排序 sorted() --> 内部比较器
    sorted(Comparator) ->外部比较器
  • 映射 map(Function fun) stream操作的每一个数据都所用于参数函数,映射成一个新的结果,最后返回一个持有所有映射后的新的结果的流

5.2 代码

public class Class002_Stream {
    public static void main(String[] args) {
        List<Employee> list = Arrays.asList(
                new Employee("bcd",27,9500),
                new Employee("aaa",29,10000),
                new Employee("abc",28,8000),
                new Employee("bc",28,9000),
                new Employee("bc",28,9000),
                new Employee("cde",30,12000)
        );


        //获取Stream
        Stream<Employee> stream = list.stream();
        //中间操作
        //过滤
        //stream = stream.filter(e-> e.getAge()>=28);
        //流式调用|链式调用
        //stream = stream.distinct().limit(3).skip(1);

        //排序
        //stream = stream.sorted();
        stream = stream.sorted((x,y)->Double.compare(y.getSalary(),x.getSalary()));  //不能通过方法引用

        Stream<String> names = stream.map(e->e.getName()).distinct();
        
		//一条语句中间加结束
        list.stream().map(e->e.getSalary()).distinct().filter(s->s>=10000).sorted().forEach(System.out::println);

        //终止行为
        //stream.forEach(System.out::println);
        names.forEach(System.out::println);
    }
}

6 终止

6.1 终止行为

  • 遍历

    • foreach(Consumer)
  • 查找与匹配

    • allMatch-检查是否匹配所有元素
    • anyMatch-检查是否至少匹配一个元素
    • noneMatch-检查是否没有匹配所有元素
    • findFirst-返回第一个元素
    • findAny-返回当前流中的任意元素
    • count-返回流中元素的总个数
    • max-返回流中最大值
    • min-返回流中最小值
  • 规约 reduce

    • map->reduce
    • 加工->计算结果
  • 收集

    • collect()

6.2 代码

public class Class003_Stream {
    public static void main(String[] args) {
        List<Employee> list = Arrays.asList(
                new Employee("bcd",27,9500),
                new Employee("aaa",29,10000),
                new Employee("abc",28,8000),
                new Employee("bc",28,9000),
                new Employee("bc",28,9000),
                new Employee("cde",30,12000)
        );

        //判断每一个员工是否都>=20岁
        boolean flag = list.stream().distinct().allMatch(e->e.getAge()>=20);
        System.out.println(flag);

        //查找薪资最高的员工
        //Optional<T> 存储一个数据的容器类型->jdk8新增的容器类型-->帮助避免空指针异常的出现
        Optional<Employee> op = list.stream().sorted((x, y)->Double.compare(y.getSalary(),x.getSalary())).findFirst();
        System.out.println(op.get());

        //parallelStream() 并行流
        System.out.println(list.stream().distinct().parallel().findAny().get());
        System.out.println(list.parallelStream().distinct().findAny().get());

        System.out.println(list.stream().filter(e->e.getSalary()<=10000).count());

        查找薪资最高的员工
        System.out.println(list.stream().distinct().max((x,y)->Double.compare(x.getSalary(),y.getSalary())).get());;

        //规约
        //找到公司所有员工的薪资,求和
        System.out.println(list.stream().map(Employee::getSalary).reduce((x,y)->x+y).get());;
        //1+2+3+4+5
        Stream<Integer> stream = Stream.of(1,2,3,4,5);
        /*System.out.println(stream.reduce((x,y)->{
            System.out.println("运算过程 : x = "+x+",y = "+y);
            return x+y;
        }).get());*/

        System.out.println(stream.reduce(100,(x,y)->{
            System.out.println("运算过程 : x = "+x+",y = "+y);
            return x+y;
        }));;

        //收集collect
        System.out.println(list.stream().distinct().count());
        //static <T> Collector<T,?,Long> counting() 返回类型为 T的 Collector接受元素,用于计算输入元素的数量。
        System.out.println(list.stream().distinct().collect(Collectors.counting()));
        //平均薪资  static <T> Collector<T,?,Double> averagingDouble(ToDoubleFunction<? super T> mapper) 返回 Collector ,它生成应用于输入元素的双值函数的算术平均值。
        System.out.println(list.stream().distinct().collect(Collectors.averagingDouble(Employee::getSalary)));

        //static <T> Collector<T,?,List<T>> toList() 返回 Collector ,将输入元素累积到新的 List 。
        System.out.println(list.stream().filter(e->e.getAge()>=28).collect(Collectors.toList()));
        //static <T> Collector<T,?,Set<T>> toSet() 返回 Collector ,将输入元素累积到新的 Set 。
        System.out.println(list.stream().filter(e->e.getAge()>=28).collect(Collectors.toSet()));

        //static <T,K,U>
        //Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper) 返回 Collector ,它将元素累积到 Map其键和值是将提供的映射函数应用于输入元素的结果。
        System.out.println(list.stream().distinct().collect(Collectors.toMap(Employee::getName,Employee::getSalary)));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值