侧边栏壁纸
  • 累计撰写 781 篇文章
  • 累计创建 1 个标签
  • 累计收到 1 条评论
标签搜索

lamda

Dettan
2021-04-10 / 0 评论 / 0 点赞 / 107 阅读 / 2,905 字
温馨提示:
本文最后更新于 2022-04-30,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
/ 后端 / JAVA / lamda

高阶函数
了解Lamda表达式之前,我们先来了解一下什么是高阶函数。在数学和计算机领域中,高阶函数是至少满足以下两个条件中一个:
1.接受一个或多个函数作为输入
2.输出一个函数

lamda可以使用 引用类型和常量,不可以使用变量。
返回值只能是定义时候的返回值

看看规则是不是和匿名内部类一样???

使用示例
new Thread( ()->{ do something there } ).start();
线程启动代码,标红的是lamda表达式。
定义treeSet的时候传入比较
TreeSet<Person> set = new TreeSet<Person>(
	(p1,p2)->{
		int result;
		result = p1.getAge()-p2.getAge();
		if(result == 0)
			result = p1.getName().compareTo(p2.getName());
		return result;
	}
);
如何声明一个Lamda表达式接口
1.
声明一个接口,加入类注解@FunctionalInterface,保证接口中未实现的方法有且只有一个,接口默认方法不计算在内,多个的话就会编译报错(这里需要思考一下为什么是一个,我个人觉得这里是Java为了实现函数式编程进行了“强扭的瓜”,的确是不太“甜”,内部的实现应该还是内部类的逻辑,这里是猜测)
@FunctionalInterface
public interface LamdaInterface {
public String apply(String name);

// 默认函数可以有
default String addLastName(String name) {
    return apply(name) + &quot;Curry&quot;;
}

}

2.
完成需要完成逻辑,就像填空题一样,所有的内容都完成了,只留下一个需要空来填,这要填的空就是要实现的函数逻辑。
public class NBAPlayer {
public String firstName;

// 具体结果还要依赖于接口方法的实现。这里就是我们要填的空
public void printName(LamdaInterface lamdaInterface) {
    System.out.println(lamdaInterface.addLastName(this.firstName));
}

}

3.
根据Lamda表达式实现内容
public static void main(String[] args) throws Exception{
        NBAPlayer nbaPlayer = new NBAPlayer();
        nbaPlayer.firstName = "Stephen";
        nbaPlayer.printName(name->name+"·");
    }
完整的步骤需要这三步,看到这里小伙伴们是不是觉得我忽悠你们了,这个写的代码感觉也不是很少呀,还是很痛苦。其实在实际开发的过程中,第1步是不需要我们自己做的,JDK在java.util.function包下有很多实例,涵盖了大部分的情况,所以不需要自己写函数式接口。大部分情况下第2步也是不需要自己做,因为大部分情况下都是去调用第三方的jar,这部分逻辑都已经实现,如果在一个团队中不是基础平台的开发人员的话,这一步接触的也比较少一点。所以对于我们来说其实只要把第三步完全掌握了就OK了。下面我们看一下JDK给我们提供的常见的函数式接口。

作者:不忘丶初心丶链接:https://www.jianshu.com/p/575443b6edeb
要点
1.
lambda表达式仅能放入如下代码:预定义使用了 @Functional 注释的函数式接口,自带一个抽象函数的方法,或者SAM(Single Abstract Method 单个抽象方法)类型。这些称为lambda表达式的目标类型,可以用作返回类型,或lambda目标代码的参数。例如,若一个方法接收Runnable、Comparable或者 Callable 接口,都有单个抽象方法,可以传入lambda表达式。类似的,如果一个方法接受声明于 java.util.function 包内的接口,例如 Predicate、Function、Consumer 或 Supplier,那么可以向其传lambda表达式。
2.
lambda表达式内可以使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的lambda表达式可以换为方法引用,因为这仅是一个参数相同的简单方法调用。
list.forEach(n -> System.out.println(n)); list.forEach(System.out::println); // 使用方法引用
然而,若对参数有任何修改,则不能使用方法引用,而需键入完整地lambda表达式,如下所示:
list.forEach((String s) -> System.out.println("*" + s + "*"));
事实上,可以省略这里的lambda参数的类型声明,编译器可以从列表的类属性推测出来。
3.
lambda内部可以使用静态、非静态和局部变量,这称为lambda内的变量捕获。
4.
Lambda表达式在Java中又称为闭包或匿名函数,所以如果有同事把它叫闭包的时候,不用惊讶。
5.
Lambda方法在编译器内部被翻译成私有方法,并派发 invokedynamic 字节码指令来进行调用。可以使用JDK中的 javap 工具来反编译class文件。使用 javap -p 或 javap -c -v 命令来看一看lambda表达式生成的字节码。大致应该长这样:
private static java.lang.Object lambda$0(java.lang.String);
6.
lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量。
List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7}); int factor = 2; primes.forEach(element -> { factor++; });
Compile time error : "local variables referenced from a lambda expression must be final or effectively final"
另外,只是访问它而不作修改是可以的,如下所示:
List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7}); int factor = 2; primes.forEach(element -> { System.out.println(factor*element); });
输出:
4 6 10 14
因此,它看起来更像不可变闭包,类似于Python。
0

评论区