神奇的lambda表达式
在jdk1.8中新增加了lambda表达式,可能有的小伙伴在github上面学习别人的项目的时候会看到有这样的符号
->
一个箭头类似于JS中的箭头函数,很神奇吧,这个就是jdk8中新增的lambda表达式。
为什么我们要使用lambda表达式
有的小伙伴可能会问为什么我们要使用lambda表达式,lambda表达式采用的是函数式编程,无需关心如何实现,并且代码非常的简洁,清晰易懂,下面我们就通过一个例子来看下传统方式和使用lambda表达式实现线程
传统的模式使用线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("ok");
}
}).start();
用lambda实现线程
new Thread(()->System.out.println("ok")).start();
可以从上面的例子中看到,传统模式写的代码很多,比较麻烦,而使用lambda来实现,非常的简单,也非常的清晰,并且是面向函数式的,无须关心它实现了内部的接口。
lambda入门
@FunctionalInterface
interface IntNumber {
int sayNumber(int i);
default int add(int x,int y){
return x + y;
}
}
public class LambdaDemo {
public static void main(String[]args){
IntNumber i1 = (i) -> i*2;
System.out.println( i1.sayNumber(100));
System.out.println( i1.add(11,13));
System.out.println("i1"+i1);
IntNumber i2 = i -> i*2;
IntNumber i3 = (int i) -> {
System.out.println("---------");
return i *2;
};
}
}
在上面中我们定义了一个IntNumber的接口,这个接口有1个默认实现sayNumber方法,也有一个jdk8的默认底层实现default add的方法,default 关键字在jdk8中新增加的,叫默认的底层实现,而在我们这个案例中,真正的默认实现是sayNumber。
(i) -> i*2;
括号里面的i 代表要操作的变量, 其中 i*2代表的是让i的值 * 2,注意当参数只有一个的时候,i的括号是可以省略的,当参数在1个以上就要加()。
IntNumber i3 = (int i) -> {
System.out.println("---------");
return i *2;
};
(int i)是明确了参数的类型是int ,右边的逻辑被{}包裹起来,这样就可以在里面写具体的业务了。
需要注意如下:
@FunctionalInterface
这个代表的是函数接口,最好在接口上加上这个注解
在lambda中变量类型的定义
在lambda中我们可以使用普通变量类型定义,也可以使用数组,也可以强转类型实现,如下:
@FunctionalInterface
interface IMath{
int add(int x,int y);
}
@FunctionalInterface
interface IMath2{
int sub(int x,int y);
}
public class TypeDemo {
public static void main(String[]args){
//变量类型的定义
IMath lambda = (x,y) -> x+ y;
System.out.println(lambda.add(1,3));
//数组里的定义
IMath[] lambdas = {(x,y) -> x + y};
for (IMath iMath : lambdas) {
iMath.add(1,2);
iMath.add(3,5);
iMath.add(7,9);
}
System.out.println(lambdas);
//强转
Object lambda2 = (IMath)(x,y) -> x + y;
//通过返回类型
IMath createLambda = CreateLambda();
TypeDemo demo = new TypeDemo();
//当有二次性的时候使用方法强转
demo.test((IMath) (x, y) -> x + y);
}
public void test(IMath math){
}
public void test(IMath2 math){
}
public static IMath CreateLambda(){
return (x,y) -> x + y;
}
}
上面定义了两个接口分别是IMath 和IMath2,并且使用了@FunctionalInterface注解来声明是一个函数接口,IMath中有一个add的方法,我们通过IMath接口来使用lambda表达式。
IMath lambda = (x,y) -> x+ y;
System.out.println(lambda.add(1,3));
在上面我说过当有2个参数及以上的时候就要加括号了,而箭头的右边 就是逻辑了,在这里我们希望 让x和y的值相加。
IMath[] lambdas = {(x,y) -> x + y};
这个是数组的定义
Object lambda2 = (IMath)(x,y) -> x + y;
当类型为Object的时候,需要进行强转
IMath createLambda = CreateLambda();
public static IMath CreateLambda(){
return (x,y) -> x + y;
}
我们可以接收一个静态方法方法这样使用也是没有问题的。
TypeDemo demo = new TypeDemo();
//当有二次性的时候使用方法强转
demo.test((IMath) (x, y) -> x + y);
public void test(IMath math){
}
public void test(IMath2 math){
}
上面定义了2个接口 IMath和IMath2当我们调用的时候会发生报错这个时候就要明确选择哪一个了,然后进行了强转的操作。
lambda常用的一些方法
消费者接口
public class FunctionDemo {
public static void main(String[]args){
Predicate<Integer> predicate = i -> i > 0;
System.out.println(predicate.test(10));
IntPredicate intPredicate = i -> i > 10;
System.out.println(":" + intPredicate.negate());
//消费者函数
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("消费了数据");
}
}
我们使用Predicate这个函数接口来使用lambda表达式
Predicate<Integer> predicate = i -> i > 0;
我们给了Integer的泛型,当参数为一个的时候可以省略括号,右边的就是业务逻辑
predicate.test(10);
这是一个断言函数和Assert一样,返回的是boolean值。
Consumer<String> consumer = s -> System.out.println(s);
Consumer是一个消费者函数,当左边的参数和右边要返回参数名称相同类型相同时候我们可以这样简写如下
System.out::println;
consumer.accept("消费了数据");
accept这个方法只能接受字符串。
在lambda中使用Function函数
public class CurryDemo {
public static void main(String[]args){
Function<Integer,Function<Integer,Integer>> t = x -> y -> x + y;
System.out.println("高阶函数:" + t.apply(1).apply(3));
Function<Integer,Function<Integer,Function<Integer,Integer>>> functions = x -> y -> z -> x + y + z;
Function<Integer,Function<Integer,Function<Integer,Function<Integer,Integer>>>>t2 = x -> y -> z -> f -> x + y + z + f;
System.out.println("高阶函数2:" + t2.apply(3).apply(4).apply(5).apply(6));
System.out.println(functions.apply(3).apply(4).apply(5));
int [] nums = {2,3,4};
Function f = functions;
for(int i = 0; i < nums.length; i++){
if(f instanceof Function){
Object obj = f.apply(nums[i]);
if (obj instanceof Function){
f = (Function) obj;
}else {
System.out.println("调用结束:" + obj);
}
}
}
}
}
使用Function这个函数来使用lambda表达式
Function<Integer,Function<Integer,Integer>> t = x -> y -> x + y;
可以看到这个Function函数接受的是Integer类型的参数,返回的是Function,然后又嵌套了一个Function,被嵌套的这个Function接受参数和返回参数都是Integer类型。
这里注意可以看出规律是一个高阶函数。
总结
lambda非常方便和JS中箭头函数十分相似,左边代表参数,箭头的右边则是逻辑业务代码,lambda语法上更加的精炼,帮我们解决很多的问题,lambda还可以结合Stream流以及jdk9中的Reactive Stream一起使用非常的强大。