lambada 表达式
1.lambada的存在来由
匿名类的一个问题是,如果匿名类的实现非常简单,例如只包含一个方法的接口,那么匿名类的语法可能看起来不实用且不清楚。在这些情况下,您通常会尝试将功能作为参数传递给另一个方法,例如当有人单击按钮时应采取的操作。Lambda表达式使您可以执行此操作,将功能视为方法参数,或将代码视为数据。
单 interface 单method
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
2.lambada理想用例
参考 java.util.function 下面的个别functionnal interfaces
Consequently, the JDK defines several standard functional interfaces, which you can find in the package java.util.function.
定义一个 Person 类
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
public int getAge() {
// ...
}
public void printPerson() {
// ...
}
}
有一个List<Person> 我们要打印出指定条件的Person信息,用lamdaba表达式实现可以这么做
方式一
public static void listConditionPerson(List<Person> person, Predicate<Person> pre, Consumer<Person> conf) {
for (Person p : person) {
if (pre.test(p))
conf.accept(p);
}
}
调用方式为:
listConditionPerson(person, person1 -> person1.getAge() > 10 && person1.getAge() <= 30, Person::printPerson);
方式二:使用泛型(generics)的模式改造一下方法,可以支持不同队形的相同功能
public static <X, Y> void processElements(
Iterable<X> source,
Predicate<X> tester,
Function <X, Y> mapper,
Consumer<Y> block) {
for (X p : source) {
if (tester.test(p)) {
Y data = mapper.apply(p);
block.accept(data);
}
}
}
调用方式为
processElements(
person,
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25,
p -> p.getEmailAddress(),
email -> System.out.println(email)
);
方式三:使用支持lambada的聚合函数(stream api)
person.stream().filter(person1 -> person1.getAge() > 10).map(p ->
p.getEmailAddress()).forEach(email -> {
System.out.println(email);
}); 并发版
person.parallelStream().filter(person1 -> person1.getAge() > 10).map(p ->
p.getEmailAddress()).forEach(email -> {
System.out.println(email);
});
lambda 语法官方介绍
bda expression looks a lot like a method declaration; you can consider lambda expressions as anonymous methods—methods without a name.
The following example, Calculator, is an example of lambda expressions that take more than one formal parameter:
public class Calculator {
interface IntegerMath {
int operation(int a, int b);
}
public int operateBinary(int a, int b, IntegerMath op) {
return op.operation(a, b);
}
public static void main(String... args) {
Calculator myApp = new Calculator();
IntegerMath addition = (a, b) -> a + b;
IntegerMath subtraction = (a, b) -> a - b;
System.out.println("40 + 2 = " +
myApp.operateBinary(40, 2, addition));
System.out.println("20 - 10 = " +
myApp.operateBinary(20, 10, subtraction));
}
}
The method operateBinary performs a mathematical operation on two integer operands. The operation itself is specified by an instance of IntegerMath. The example defines two operations with lambda expressions, addition and subtraction. The example prints the following:
40 + 2 = 42
20 - 10 = 10
Accessing Local Variables of the Enclosing Scope
Like local and anonymous classes, lambda expressions can capture variables; they have the same access to local variables of the enclosing scope. However, unlike local and anonymous classes, lambda expressions do not have any shadowing issues (see Shadowing for more information). Lambda expressions are lexically scoped. This means that they do not inherit any names from a supertype or introduce a new level of scoping. Declarations in a lambda expression are interpreted just as they are in the enclosing environment. The following example, LambdaScopeTest, demonstrates this:
import java.util.function.Consumer;
public class LambdaScopeTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
// The following statement causes the compiler to generate
// the error "local variables referenced from a lambda expression
// must be final or effectively final" in statement A:
//
// x = 99;
Consumer<Integer> myConsumer = (y) ->
{
System.out.println("x = " + x); // Statement A
System.out.println("y = " + y);
System.out.println("this.x = " + this.x);
System.out.println("LambdaScopeTest.this.x = " +
LambdaScopeTest.this.x);
};
myConsumer.accept(x);
}
}
public static void main(String... args) {
LambdaScopeTest st = new LambdaScopeTest();
LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
This example generates the following output:
x = 23
y = 23
this.x = 1
LambdaScopeTest.this.x = 0
If you substitute the parameter x in place of y in the declaration of the lambda expression myConsumer, then the compiler generates an error:
Consumer<Integer> myConsumer = (x) -> {
// ...
}
The compiler generates the error "variable x is already defined in method methodInFirstLevel(int)" because the lambda expression does not introduce a new level of scoping. Consequently, you can directly access fields, methods, and local variables of the enclosing scope. For example, the lambda expression directly accesses the parameter x of the method methodInFirstLevel. To access variables in the enclosing class, use the keyword this. In this example, this.x refers to the member variable FirstLevel.x.
However, like local and anonymous classes, a lambda expression can only access local variables and parameters of the enclosing block that are final or effectively final. For example, suppose that you add the following assignment statement immediately after the methodInFirstLevel definition statement:
void methodInFirstLevel(int x) {
x = 99;
// ...
}
Because of this assignment statement, the variable FirstLevel.x is not effectively final anymore. As a result, the Java compiler generates an error message similar to "local variables referenced from a lambda expression must be final or effectively final" where the lambda expression myConsumer tries to access the FirstLevel.x variable:
System.out.println("x = " + x);
Target Typing
How do you determine the type of a lambda expression? Recall the lambda expression that selected members who are male and between the ages 18 and 25 years:
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
This lambda expression was used in the following two methods:
public static void printPersons(List<Person> roster, CheckPerson tester)in Approach 3: Specify Search Criteria Code in a Local Classpublic void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester)in Approach 6: Use Standard Functional Interfaces with Lambda Expressions
When the Java runtime invokes the method printPersons, it's expecting a data type of CheckPerson, so the lambda expression is of this type. However, when the Java runtime invokes the method printPersonsWithPredicate, it's expecting a data type of Predicate<Person>, so the lambda expression is of this type. The data type that these methods expect is called the target type. To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type:
Variable declarations
Assignments
Return statements
Array initializers
Method or constructor arguments
Lambda expression bodies
Conditional expressions,
?:Cast expressions
Target Types and Method Arguments
For method arguments, the Java compiler determines the target type with two other language features: overload resolution and type argument inference.
Consider the following two functional interfaces ( java.lang.Runnable and java.util.concurrent.Callable<V>):
public interface Runnable {
void run();
}
public interface Callable<V> {
V call();
}
The method Runnable.run does not return a value, whereas Callable<V>.call does.
Suppose that you have overloaded the method invoke as follows (see Defining Methods for more information about overloading methods):
void invoke(Runnable r) {
r.run();
}
<T> T invoke(Callable<T> c) {
return c.call();
}
Which method will be invoked in the following statement?
String s = invoke(() -> "done");
The method invoke(Callable<T>) will be invoked because that method returns a value; the method invoke(Runnable) does not. In this case, the type of the lambda expression () -> "done" is Callable<T>.
博客新手,勿喷!
lambada 表达式的更多相关文章
- 2.cocos2dx 3.2中语法的不同之处,lambada表达式的使用和function和bind函数的使用
1 打开建好的T32 Cocos2dx-3.2的一个项目 2 设置Cocos显示窗口的位置是在AppDelegate.cpp中: 3 设置自适应窗口大小的代码是在上面的 ...
- 阐述Lambada表达式
在C#2.0引入匿名方法之前,声明委托的唯一方法就是使用命名方法,C#2.0之后的C#3.0中开始引入了Lambda表达式取代了匿名方法. 匿名方法 要说Lambda必然离不开匿名方法,实际上,Lam ...
- lambada表达式
在Java 8中stream().map(),您可以将对象映射为其他对象. List<String> collect = alpha.stream().map(String::toUppe ...
- Lambada表达式的作用
Lambda函数的用处 假设你设计了一个地址簿的类.现在你要提供函数查询这个地址簿,可能根据姓名查询,可能根据地址查询,还有可能两者结合.要是你为这些情况都写个函数,那么你一定就跪了.所以你应该提 ...
- 2.cocos2dx 3.2在语法的差异,lambada使用表达式和function和bind使用功能
1 打开 - 内置T32 Cocos2dx-3.2一个专案 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhb ...
- Lambda表达式的由来
1.lambada表达式的本质:一个匿名方法,或说是匿名委托.从C#3.0开始支持,C#2.0只支持匿名方法语法很简单 : (输入参数)=>expr //当参数为一个是可以省略括号.lamb ...
- 表达式目录树(Expression)
一:什么是表达式树 Expression我们称为是表达式树,是一种数据结构体,用于存储需要计算,运算的一种结构,这种结构可以只是存储,而不进行运算.通常表达式目录树是配合Lambda一起来使用的,la ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- 浅入浅出Lambda表达式
大家在开发中会经常看到也会经常使用lambda表达式. 园子里也有很多详解lambda表达式的文章,多是从横向来讲述. 但lambda表达式到底如何变成现在这个样子,表达式的形式到底代表什么含义,这些 ...
随机推荐
- Linux上用IP转发使内部网络连接互联网
IP转发的概念: 使 Linux 机器像路由器一样将数据从一个网络发送到另一个网络.所以,它能作为一个路由器或者代理服务器,实现将一个连接的互联网或者网络连接共享给多个客户端机器. 1. 启用 IPv ...
- 分布式Redis的分布式锁 Redlock
链接 Distributed locks with Redis 引言 之前自己在用redis来实现分布式锁的时候都是基于单个Redis实例,也就是说Redis本身是有单点故障的,Redis的官方文档介 ...
- React: 通过React.Children访问特定子组件
一.简介 React中提供了很多常用的API,其中有一个React.Children可以用来访问特定组件的子元素.它允许用来统计个数.map映射.循环遍历.转换数组以及显示指定子元素,如下所示: va ...
- SpringCloud路由网关Zuul
一.什么是网关 Zuul的主要功能是路由转发和过滤器.路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务.zuul默认和Ribbon结合实现了 ...
- Spring Cloud Finchley.SR1 版本的坑:placeholer占位符无法解析!
接入nacos 之后,想把所有的配置丢上去. 启动程序是: @EnableDiscoveryClient @RestController @ComponentScan(basePackages = { ...
- 对token机制的学习和分析
token,中文意思为令牌,是用户登录后会返回的一个字符串,里面包括用户信息.登录时间等,但是是加密过的密文,其加解密方式由后端决定. 在登录之后的接口请求中,前端需在请求中统一加上token,从而识 ...
- Jmeter工具使用初体验
一.Jmeter组成部分 一个完整的脚本必须包含以下三项,他们都在测试计划的子选项中,我们直接在测试计划上右键选择即可 线程组 取样器 监视器 二.脚本编写 1.创建线程组 2.添加取样器 我们这里添 ...
- SpringBoot2 配置多数据源,整合MybatisPlus增强插件
本文源码:GitHub·点这里 || GitEE·点这里 一.项目案例简介 1.多数据简介 实际的项目中,经常会用到不同的数据库以满足项目的实际需求.随着业务的并发量的不断增加,一个项目使用多个数据库 ...
- 使用Docker Compose 部署Nexus后初次登录账号密码不正确,并且在nexus-data下没有admin,password
场景 Ubuntu Server 上使用Docker Compose 部署Nexus(图文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/ ...
- C# Excel 读取导入数据库
使用Aspose.Cells组件. 表格第一行为表头合并,第二行为数据名称,从第三行开始数据. if (xtraOpenFileDialog1.ShowDialog() == DialogResult ...