lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method)。将Lambda表达式引入JAVA中的动机源于一个叫“行为参数”的模式。这种模式可以解决需求变化带来的问题,使代码变得更加灵活。在JAVA8以前,参数模式十分啰嗦。Lambda表达式经过精简的方式使用行为模式克服了这个缺点php
函数式编程html
public class ScopeTest {
@Test
public void test_scope(){
Runnable runnable = () -> {
this.print();
};
runnable.run();
}
private void print(){
System.out.println("I can print");
}
}
复制代码
final
labmda表达式使用外部的变量时,不可修改,默认定义成final java
函数式接口
只有一个抽象方法的接口咱们就称之为功能性接口,又简称 SAM 类型,即 Simple Abstract Method。会写上注释 @FunctionalInterface编程
//用这个注解来表示功能性接口
public interface Consumer<T> {
/** * Performs this operation on the given argument. * * @param t the input argument */
void accept(T t);
}
复制代码
常见的内置函数以下:数组
java.lang.Runnable 执行动做服务器
java.util.function.Predicate 接收T对象并返回boolean闭包
java.util.function.Consumer 接收T对象,不返回值app
java.util.function.Function<T,R> 接收T对象,返回R对象.函数式编程
java.util.function.Supplier 提供T对象(例如工厂),不接收值函数
方法引用
方法引用有不少种,它们的语法以下:
静态方法引用:ClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:ClassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new
@Test
public void test_instance(){
Set<String> girls = new HashSet<>();
Set<String> names = new HashSet<>();
names.stream()
//实例::methodName
.filter(girls::contains)
.collect(Collectors.toList());
}
@Test
public void test_this(){
Set<String> names = new HashSet<>();
names.stream()
//this::methodName
.filter(this::hasAuth)
.collect(Collectors.toList());
}
private boolean hasAuth(String authKey){
return true;
}
复制代码
Map<String,Person> map = new HashMap<>();
map.forEach((String name,Person person)->{
person.fly();
System.out.println(name+":"+person);
});
map.forEach((name,person)->{
// 无须判断类型,自动根据上下文推断
person.fly();
System.out.println(name+":"+person);
});
复制代码
/** * 正常的代码 */
@Test
public void test_person(){
CnResult<Person> result = null;
try {
// 只有这里取值是不一样的,其余的处理是同样的,包括try,catch,打日志,定义异常等
Person entity = this.getPerson();
result = CnResult.success(entity);
}catch (CnException e){
logger.error(e.getMessage(),e);
result = CnResult.error(e.getErrorCode(),e.getMessage());
}
catch (Exception e) {
logger.error(e.getMessage(),e);
result = CnResult.error("1-1-1-1",e.getMessage());
}
Assert.assertNotNull(result);
}
@Test
public void test_animal(){
CnResult<Animal> result = null;
try {
// 只有这里取值是不一样的,其余的处理是同样的,包括try,catch,打日志,定义异常等
Animal entity = this.getAnimal();
result = CnResult.success(entity);
}catch (CnException e){
logger.error(e.getMessage(),e);
result = CnResult.error(e.getErrorCode(),e.getMessage());
}
catch (Exception e) {
logger.error(e.getMessage(),e);
result = CnResult.error("1-1-1-1",e.getMessage());
}
Assert.assertNotNull(result);
}
/** * lambda代码 */
@Test
public void test_lambda(){
//屏蔽全部细节,只把获取对象的逻辑传递进去
CnResult<Person> person = WapperUtils.wapper(this::getPerson);
Assert.assertNotNull(person);
CnResult<Animal> animal = WapperUtils.wapper(this::getAnimal);
Assert.assertNotNull(animal);
}
public class WapperUtils {
private static final Logger logger = LoggerFactory.getLogger(WapperUtils.class);
/** * 包裹 * * @param supplier * @param <T> * @return */
public static <T> CnResult<T> wapper(Supplier<T> supplier){
try {
T entity = supplier.get();
CnResult<T> cnResult = CnResult.success(entity);
return cnResult;
}catch (CnException e){
logger.error(e.getMessage(),e);
return CnResult.error(e.getErrorCode(),e.getMessage());
}
catch (Exception e) {
logger.error(e.getMessage(),e);
return CnResult.error("1-1-1-1",e.getMessage());
}
}
}
复制代码
只要是代码片断,找到变点化,抽象成lambda,把固定的代码统一封装,就能够使用行为的复用,减小代码片断和代码包裹。
明确语义
@Test
public void test_first() {
List<Person> persons = new ArrayList<>();
persons.stream()
/** * 没有明确的语义。须要根据过程计算推理得出结果,也不清楚背后的业务和场景 * */
.filter(person -> person.getAge() >= 18)
.collect(Collectors.toList());
}
@Test
public void test_second() {
List<Person> persons = new ArrayList<>();
persons.stream()
.filter(person -> {
/** * 若是职责变动,得修改代码结构,并且代码愈来愈难理解 */
if (person.getAge() >= 18) {
return true;
}
if (person.getName().startsWith("庄")) {
return true;
}
return false;
})
.collect(Collectors.toList());
}
@Test
public void test_third() {
List<Person> persons = new ArrayList<>();
persons.stream()
/** * 随着业务变动须要不断添加filter */
.filter(person -> person.getAge() >= 18)
.filter(person -> person.getName().startsWith("庄"))
.collect(Collectors.toList());
}
@Test
public void test_fourth() {
List<Person> persons = new ArrayList<>();
persons.stream()
/** * 随着业务变动须要不断添加filter */
.filter(Person::isAdult)
.filter(Person::belongToZhuang)
.collect(Collectors.toList());
}
@Test
public void test_final() {
List<Person> persons = new ArrayList<>();
/** * 有明确的语义,不用再面向细节加工一下,并且也方便后面的扩展 */
persons.stream()
.filter(Person::hasAuth)
.collect(Collectors.toList());
}
复制代码
@Test
public void test_name_bad(){
List<Person> persons = new ArrayList<>();
/** * lambda一多的时候,没有明确的参数,计算和理解起来很是吃力。 */
persons.stream()
.filter(e->e.getAge()>18)
.map(e->e.getName())
.filter(e->e.startsWith("庄"))
.collect(Collectors.toList());
}
@Test
public void test_name(){
List<Person> persons = new ArrayList<>();
persons.stream()
.filter(person->person.getAge()>18)
.map(person->person.getName())
.filter(name->name.startsWith("庄"))
.collect(Collectors.toList());
}
复制代码
参数须要有明确语义
逻辑复杂
@Test
public void test_bad() {
List<Integer> values = new ArrayList<>();
int result = values.stream().mapToInt(e -> {
int sum = 0;
for (int i = 0; i < e; i++) {
if (e % i == 0) {
sum += i;
}
}
return sum;
}).sum();
System.out.println(result);
}
@Test
public void test_() {
List<Integer> values = new ArrayList<>();
int result = values.stream().mapToInt(this::toInt).sum();
System.out.println(result);
}
private Integer toInt(int e) {
int sum = 0;
for (int i = 0; i < e; i++) {
if (e % i == 0) {
sum += i;
}
}
return sum;
}
复制代码
建议把多行lambda表达式主体转移到一个命名函数中,而后使用方法引用
腾讯云如今作活动,新手福利1000减750,云服务器最低2折,1核2G内存50G硬盘3年最低只要600元!戳此了解详情!
转自:https://www.cnblogs.com/ansn001/p/9399360.html