栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java8新特性-Lambda表达式与函数式接口

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java8新特性-Lambda表达式与函数式接口

文章目录
  • 1. 为什么使用 Lambda 表达式
  • 2. Lambda 表达式的本质与函数式接口
  • 3. Lambda 表达式的使用
    • (1) 无参,且无返回值
    • (2) 一个参数,无返回值
    • (3) 形参的数据类型可以省略,编译器可以由编译类型推断得出
    • (4) 形参若只需要一个参数时,参数的小括号可以省略
    • (5) 两个或两个以上参数,多条执行语句,并且可以有返回值
    • (6) 当 Lambda体 只有一条语句时,关键字return 和 方法体的大括号都可以省略
    • 小结:Lambda 表达式使用的总结
  • 4. 函数式接口与Lambda表达式结合的示例
    • 4.1 消费型接口的使用
    • 4.2 断定型接口的使用

1. 为什么使用 Lambda 表达式

Lambda 表达式是一个 匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样可以传递)。使用它可以写出更简洁、灵活的代码。

2. Lambda 表达式的本质与函数式接口

Lambda 表达式在 Java 中本质还是一个对象,它针对的是函数式接口,它可以产生函数式接口的一个匿名实现类的实例。

所以,以前我们用匿名实现类实现的代码,都可以通过Lambda 表达式来更简单的书写。

能够用Lambda 表达式实现的接口有一定的要求,就是接口中只能有唯一的一个抽象方法。正因为只有唯一的一个抽象方法需要去实现,所以Lambda 表达式不需要我们去指明到底是哪一个方法需要去实现。

而一个接口中,如果只声明了一个抽象方法,则此接口就称为函数式接口。

我们举两个例子来展示函数式接口长什么样:

@FunctionalInterface
public interface Runnable {
	
	public abstract void run();
}
@FunctionalInterface
public interface Comparator {
	
	int compare(T o1, T o2);
}

我们也可以自己定义一个函数式接口玩一玩:

// @FunctionalInterface 这个注解加不加都不影响MyInterface是一个函数接口的事实
// 不加一样也可以使用我们后面即将讲到的Lambda 表达式
// 此注解 仅仅起到检验的作用
@FunctionalInterface
public interface MyInterface {
	public abstract void method(T o);
}

我们可以在一个函数式接口上使用 @ F u n c t i o n a l I n t e r f a c e @FunctionalInterface @FunctionalInterface 注解,这样做可以检验它是否是一个函数式接口。同时,javadoc也会包含一条声明,说明该接口是一个函数式接口。

在 java.util.function 包下,定义了丰富的函数式接口,注意下图中'函数型接口' 和我们之前一直提到的'函数式接口' 的差异。

3. Lambda 表达式的使用
  1. 举例: (o1, o2) -> Integer.compare(o1, o2);
  2. 格式:
    ->:Lambda操作符 或 箭头操作符
    ->左侧 :Lambda形参列表 (其实就是接口中抽象方法的形参列表)
    ->右侧 :Lambda体 (其实就是重写的抽象方法的方法体)
(1) 无参,且无返回值
// 匿名内部类写法
Runnable r1 = new Runnable() {	// 父类引用指向子类对象
	@Override
	public void run() {
		while (true) {
			System.out.println("线程正在执行中~~~");
		}
	}
};

// 等价于
Runnable r2 = () -> {	// lambda 方法体
	while (true) {
		System.out.println("线程正在执行中~~~");
	}
};
(2) 一个参数,无返回值
// 消费型接口:只接收参数,但是无返回值
Consumer consumer = new Consumer() {	// 父类引用指向子类对象
	@Override
	public void accept(String s) {
		System.out.println(s);
	}
};

// 等价于
Consumer consumer = (String s) -> {
	System.out.println(s);
};
(3) 形参的数据类型可以省略,编译器可以由编译类型推断得出
// 类型推断,可以省略参数
Consumer consumer = (String s) -> {
	System.out.println(s);
};

// 等价于
Consumer consumer = (s) -> {
	System.out.println(s);
};

// 类型推断不仅Lambda表达式中有,讲集合的时候也用到过
ArrayList list = new ArrayList();
// 可以直接写为
ArrayList list = new ArrayList<>();
(4) 形参若只需要一个参数时,参数的小括号可以省略
// 参数唯一时,可以省略小括号
Consumer consumer = (s) -> {
	System.out.println(s);
};
// 等价于
Consumer consumer = s -> {
	System.out.println(s);
};
(5) 两个或两个以上参数,多条执行语句,并且可以有返回值
Comparator comparator = new Comparator() {
	@Override
	public int compare(Integer o1, Integer o2) {
		System.out.println(o1);
		System.out.println(o2);	// 模拟通用情况,有多条语句
		return o1.compareTo(o2);
	}
};

// 等价于
Comparator comparator = (o1, o2) -> {
	System.out.println(o1);
	System.out.println(o2);	// 模拟通用情况,有多条语句
	return o1.compareTo(o2);
};
(6) 当 Lambda体 只有一条语句时,关键字return 和 方法体的大括号都可以省略
// 例子1:
Comparator comparator = (o1, o2) -> {
	return o1.compareTo(o2);
};

// 等价于(return和{}要么同时不写,要么同时写)
Comparator comparator = (o1, o2) -> o1.compareTo(o2);
// 例子2:
Consumer consumer = s -> {
	System.out.println(s);
};

// 等价于
Consumer consumer = s -> System.out.println(s);
小结:Lambda 表达式使用的总结

-> 左侧:Lambda形参列表的参数类型可以省略(编译类型自动推断);如果Lambda形参列表只有一个参数,其()可以省略;
-> 右侧:Lambda体应该使用一对{}进行包裹;如果Lambda体只有一条执行语句(可能是return语句),可以省略{}和return关键字。

4. 函数式接口与Lambda表达式结合的示例 4.1 消费型接口的使用
public class Main {
	@Test
	public void testOldWay() {	// 匿名实现类的方式
		spendMoney(500, new Consumer() {
			@Override
			public void accept(Double money) {
				System.out.println("消费了 " + money + " 元。");
			}
		});
	}

	@Test
	public void testNewWay() { // 使用Lambda 表达式的方式
		spendMoney(500, money -> System.out.println("消费了 " + money + " 元。"));
	}
	
	public void spendMoney(double money, Consumer consumer) {
		consumer.accept(money);
	}
}
4.2 断定型接口的使用
public class Main {
	private List list = Arrays.asList("北京", "南京", "天津", "吴京", "普京");
	@Test
	public void testOldWay() {	// 传统匿名实现类的方式,筛选含"京"的字符串
		List newStrs = filterString(list, new Predicate() {
			@Override
			public boolean test(String s) {
				return s.contains("京");
			}
		});
	}

	@Test
	public void testNewWay() {	// 使用Lambda 表达式的方式,筛选含"京"的字符串
		List newStrs = filterString(list, s -> s.contains("京"));
	}
	
	// 根据传入的规则,过滤集合中的字符串。此规则由Predicate接口的实现类决定
	public List filterString(List list, Predicate predicate) {
		ArrayList newList = new ArrayList<>();
		for (String s : list) {
			if (predicate.test(s)) {
				newList.add(s);
			}
		}
		return newList;
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/434259.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号