前言:
这两天彻底的复习了一遍java8的各种新特性,趁着热乎劲,把知识点整理成博客的形式保存一下。
一、lambda介绍
lambda表达式 : 也可称为闭包,lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中),免去了使用匿名方法的麻烦,并且给予java简单但是强大的函数化的编程能力
语法格式:
(parameters) -> expression
或者
(parameters) ->{ statements; }格式说明:
():接口中抽象方法的参数列表,没有参数就空着,有参数则写出参数,多个参数用逗号分隔
->:传递的意思,将参数传递给方法体{}
{}:重写接口的抽象方法的方法体
二、lambda用法实例
1.简单实例(基础用法的规则)
1.1 无参数时,可以省略括号内容
()->10 //返回结果值:10
1.2 传入string类型的参数
(string s)->system.out.print(s) //打印s的内容
1.3 传入的参数类型可以省略,如下
// a->a*10 //返回结果值:a*10(传入一个参数时,可以省略括号) (a,b)->a*b //返回结果值:a*b(传入两个或以上参数时,不能省略括号,)
2.函数式接口
2.1 lambda实现自定义接口calculator
首先定义一个函数式接口 calculator
,包含唯一一个抽象方法 calcu()
public interface calculator { public abstract int calcu(int x, int y); }
其次定义一个 invokecalcu()
,接收参数类型为接口
public static void invokecalcu(int x, int y, calculator calculator) { int sum = calculator.calcu(x, y); system.out.println("sum = " + sum); }
最后调用 invokecalcu()
,一共有三种方法实现:
1)使用匿名内部类传入接口,并实现抽象方法
invokecalcu(10, 20, new calculator() { @override public int calcu(int x, int y) { return x + y; } });
2)使用lambda表达式,简化操作
invokecalcu(120, 130, (a, b) -> a + b);
2.2 lambda表达式实现多线程接口实例 runnable
//使用匿名内部类的方式实现多线程的创建 new thread(new runnable() { @override public void run() { system.out.println("currentthreadname = " + thread.currentthread().getname()); } }).start(); //使用lambda表达式实现多线程 new thread(() -> system.out.println("currentthread().getname() = " + thread.currentthread().getname())).start();
2.3 lambda表达式实现比较器接口实例 comparator
定义一个person类,保存姓名和年龄
public class person { private string name; private int age; public person() { } public person(string name, int age) { this.name = name; this.age = age; } @override public string tostring() { return "person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public string getname() { return name; } public void setname(string name) { this.name = name; } public int getage() { return age; } public void setage(int age) { this.age = age; } }
然后分别使用匿名内部类和lambda表达式对person类的年龄进行排序
person[] arr = { new person("佟丽娅", 26), new person("范冰冰", 22), new person("柳岩", 21) }; //匿名内部类重写comparator接口里的compare() system.out.println("=======匿名内部类升序排序:================="); arrays.sort(arr, new comparator<person>() { @override public int compare(person o1, person o2) { return o1.getage() - o2.getage(); } }); for (person person : arr) { system.out.println(person); } //使用lambda表达式,简化匿名内部类 system.out.println("=======lambda表达式降序排序:==============="); arrays.sort(arr, (o1, o2) -> o2.getage() - o1.getage()); /** * jdk1.8 也可以这样写 方法引用 * arrays.sort(arr,comparator.comparingint(person::getage).reversed()); **/ for (person person : arr) { system.out.println(person); } //stream api 也是java8的新特新写法 system.out.println("=======stream-sort升序排序:==============="); arrays.stream(arr).sorted(comparator.comparing(person::getage)).foreach(system.out::println);
接口中 有且仅有唯一一个抽象方法 ,称之为函数式接口(这种类型的接口也称为sam接口,即single abstract method interfaces)
使用前提:
- 使用lambda必须具有接口,且要求接口中有且仅有一个抽象方法
- 无论是 jdk内置的
runnable
、comparator
接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用lambda- 使用lambda必须具有上下文推断
方法的参数或局部变量类型必须为lambda对应的接口类型,才能使用lambda作为该接口的实例
有且仅有一个抽象方法的接口,称为
“函数式编程”
三、lambda变量作用域
3.1在 lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量
string[] str = {"1","12","123"}; comparator<string> comparator = (str, second) -> integer.compare(str.length(), second.length()); //str处的编译会出错
3.2 lambda 表达式只能引用标记了 final 的外层局部变量
也就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
可以直接在 lambda 表达式中访问外层的局部变量:
public static void main(string args[]) { final int num = 1; converter<integer, string> s = (param) -> system.out.println(string.valueof(param + num)); s.convert(2); // 输出结果为 3 } public interface converter<t1, t2> { void convert(int i); }
lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
int num = 1; converter<integer, string> s = (param) -> system.out.println(string.valueof(param + num)); s.convert(2); num = 5; //由于在lambda表达式中引用了num,所以num是隐形的final修饰,但是这里修改了num的值,final就不存在了
如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!
网友评论