lambda表达式 函数式接口 方法引用

  • 时间:
  • 浏览:
  • 来源:互联网

文章主要参考尚硅谷

Java 8新特性简介

 速度更快
 代码更少(增加了新的语法 Lambda 表达式)
 强大的 Stream API
 便于并行
 最大化减少空指针异常 Optional

其中最为核心的为 Lambda 表达式与Stream API

1. Lambda 表达式

1.1 为什么使用 Lambda 表达式

Lambda 是一个匿名函数,我们可以把 Lambda
表达式理解为是一段可以传递的代码(将代码
像数据一样进行传递)。可以写出更简洁、更
灵活的代码。作为一种更紧凑的代码风格,使
Java的语言表达能力得到了提升。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 Lambda 表达式语法

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
在这里插入图片描述
在这里插入图片描述

1.3 类型推断

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”.

2. 函数式接口

2.1 什么是函数式接口

  1. 只包含一个抽象方法的接口,称为函数式接口。
  2. 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
  3. 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

2.2 自定义函数式接口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。

2.3 Java 内置四大核心函数式接口

在这里插入图片描述

public class TestLambda {
	
	List<Employee> emps = Arrays.asList(
			new Employee(101, "张三", 18, 9999.99),
			new Employee(102, "李四", 59, 6666.66),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);
	
	@Test
	public void test1(){
		Collections.sort(emps, (e1, e2) -> {
			if(e1.getAge() == e2.getAge()){
					return e1.getName().compareTo(e2.getName());
			}else{
				return -Integer.compare(e1.getAge(), e2.getAge());
			}
		});
		
		for (Employee emp : emps) {
			System.out.println(emp);
		}
	}
	
	@Test
	public void test2(){
		String trimStr = strHandler("\t\t\t 威武   ", (str) -> str.trim());
		System.out.println(trimStr);
		
		String upper = strHandler("abcdef", (str) -> str.toUpperCase());
		System.out.println(upper);
		
		String newStr = strHandler("威武", (str) -> str.substring(2, 5));
		System.out.println(newStr);
	}
	
	//需求:用于处理字符串
	public String strHandler(String str, MyFunction mf){
		return mf.getValue(str);
	}
	
	@Test
	public void test3(){
		op(100L, 200L, (x, y) -> x + y);
		
		op(100L, 200L, (x, y) -> x * y);
	}
	
	//需求:对于两个 Long 型数据进行处理
	public void op(Long l1, Long l2, MyFunction2<Long, Long> mf){
		System.out.println(mf.getValue(l1, l2));
	}

}
/*
 * Java8 内置的四大核心函数式接口
 * 
 * Consumer<T> : 消费型接口
 * 		void accept(T t);
 * 
 * Supplier<T> : 供给型接口
 * 		T get(); 
 * 
 * Function<T, R> : 函数型接口
 * 		R apply(T t);
 * 
 * Predicate<T> : 断言型接口
 * 		boolean test(T t);
 * 
 */
public class TestLambda3 {
	
	//Predicate<T> 断言型接口:
	@Test
	public void test4(){
		List<String> list = Arrays.asList("Hello", "Lambda", "www", "ok");
		List<String> strList = filterStr(list, (s) -> s.length() > 3);
		
		for (String str : strList) {
			System.out.println(str);
		}
	}
	
	//需求:将满足条件的字符串,放入集合中
	public List<String> filterStr(List<String> list, Predicate<String> pre){
		List<String> strList = new ArrayList<>();
		
		for (String str : list) {
			if(pre.test(str)){
				strList.add(str);
			}
		}
		
		return strList;
	}
	
	//Function<T, R> 函数型接口:
	@Test
	public void test3(){
		String newStr = strHandler("\t\t\t 威武   ", (str) -> str.trim());
		System.out.println(newStr);
		
		String subStr = strHandler("威武", (str) -> str.substring(2, 5));
		System.out.println(subStr);
	}
	
	//需求:用于处理字符串
	public String strHandler(String str, Function<String, String> fun){
		return fun.apply(str);
	}
	
	//Supplier<T> 供给型接口 :
	@Test
	public void test2(){
		List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
		
		for (Integer num : numList) {
			System.out.println(num);
		}
	}
	
	//需求:产生指定个数的整数,并放入集合中
	public List<Integer> getNumList(int num, Supplier<Integer> sup){
		List<Integer> list = new ArrayList<>();
		
		for (int i = 0; i < num; i++) {
			Integer n = sup.get();
			list.add(n);
		}
		
		return list;
	}
	
	//Consumer<T> 消费型接口 :
	@Test
	public void test1(){
		happy(10000, (m) -> System.out.println("消费:" + m + "元"));
	} 
	
	public void happy(double money, Consumer<Double> con){
		con.accept(money);
	}
}

2.4 练习

public static void main(String[] args) {
    String str = "\t\t\tHello World             ";
    System.out.println("str = " + str);
    System.out.println(handleString(str, s -> s.substring(0, 5)));
    System.out.println(handleString(str, s -> s.trim()));
    System.out.println(handleString(str, s -> s.toLowerCase()));
}
/**
     * 字符串处理
     * 
     * @param str
     * @param function1
     * @return
     */
public static String handleString(String str, MyFunction1 function1) {
    return function1.handlerString(str);
}

// 2. 根据学生的成绩从小到大排序, 如果成绩一样, 则按照年龄从小到大排序.
        Student[] students = {
                new Student(1l, 18, 99d),
                new Student(1l, 17, 99d),
                new Student(1l, 18, 69d)
        };

        List<Student> list = Arrays.asList(students);
        System.out.println("list = " + list);
        Collections.sort(list, (s1, s2) -> {
            int substract = Double.compare(s1.getExamResult(), s2.getExamResult());
            if (substract == 0) {
                return Integer.compare(s1.getAge(), s2.getAge());
            }
            return substract;
        });

        System.out.println("list = " + list);
// 3. 计算2个long类型数据差和乘积

        System.out.println(operation(1D, 3D, (MyFunction2<Double>) (i1, i2) -> i1 + i2));
 public static String handleString(String str, MyFunction1 function1) {
        return function1.handlerString(str);
    }

3. 方法引用与构造器引用

3.1 方法引用

什么时候使用方法引用?
当Lambda体的操作,已经有实现的方法了,可以使用方法引用!
三种主要使用情况:

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

方法引用注意事项

  1. 实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
  2. 方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
  3. 如果我们引用的方法的第一个参数是调用对象, 而且使用 ClassName::methodName这种方式调用的时候, 那么我们的抽象方法的参数需要比引用方法的参数多一个。

举栗


BinaryOperator<Integer> binaryOperator = (x, y) -> Math.max(x, y);
System.out.println(binaryOperator.apply(1, 3));

public static void main(String[] args) {
    accept("Method Reference!!!", x -> System.out.println(x));
    accept("Method Reference!!!", System.out::println);
}
private static void accept(Object obj, Consumer consumer) {
    consumer.accept(obj);
}

对象名::实例方法名

PrintStream out = System.out;
Consumer<Object> consumer = x -> out.println(x);
consumer.accept("Method Reference");
consumer = out::println;
consumer.accept("Hi");
consumer = System.out::println;
consumer.accept("Perfect");

Student student = new Student(1L, 18, 99.0);
// Supplier<Double> supplier = () -> student.getExamResult();
Supplier<Double> supplier = student::getExamResult;
System.out.println(supplier.get());

类名 :: 静态方法名

Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
System.out.println(comparator.compare(1, 1));

类名::实例方法名

BiPredicate<String, String> biPredicate = (x, y) -> x.equals(y);
System.out.println(biPredicate.test("one", "one"));
biPredicate = String::equals;
System.out.println(biPredicate.test("two", "one"));

3.2 构造器引用

格式: ClassName::new
构造器参数列表要与接口中抽象方法的参数列表一致!

Supplier<Student> supplier = () -> new Student();
System.out.println(supplier.get());
Function<Long, Student> function = (x) -> new Student(x);
System.out.println(function.apply(1L));

Supplier<Student> supplier = Student::new;
System.out.println(supplier.get());
Function<Long, Student> function = Student::new;
System.out.println(function.apply(1L));

3.3 数组引用

格式: type[] :: new

Supplier<int[]> supplier = () -> new int[1];
System.out.println(supplier.get().length);
Function<Integer, Student[]> function = len -> new Student[len];
System.out.println(function.apply(10).length);

Function<Integer, Student[]> function = Student[]::new;
System.out.println(function.apply(10).length);

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

本文链接http://metronic.net.cn/metronic/show-22251.html