Java从入门到精通十四(Lambda表达式)
- Lambda的引入体验
- 实例一(抽象方法无参无返回值)
- 实例二(抽线方法有参无返回值)
- 实例三(抽象方法带参带返回值)
- lambda的表达式的简化操作
- 匿名内部类和lambda的使用区别
Lambda的引入体验
lambda是java8之后的一个新的特性。我当时学java的时候还没有见过这个表达式。主要是lambda简化了代码块,在某些方面,是比匿名内部类更加方便地。但是并不能完全替代匿名内部类。在使用地方面,还是有区别地,具体的,后面说。
还记得自己创建线程吗?一种是自己去继承Thread然后实现run()方法。这是基本的,如果还需要自己再重写一些方法,也可以去实现。就像这样。
代码语言:javascript复制package demo.LambdaDemo;
public class LambdaDemo extends Thread{
@Override
public void run() {
for(int i=0;i<100;i )
{
System.out.println(Thread.currentThread().getName() ":" i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public LambdaDemo(String name) {
super(name);
}
public LambdaDemo() {
super();
}
public static void main(String[] args) {
LambdaDemo ld = new LambdaDemo("线程1");
LambdaDemo ld1 = new LambdaDemo("线程2");
ld.start();
ld1.start();
}
还可以去实现Runable接口 先定义一个类,实现Runable接口。
代码语言:javascript复制package demo.LambdaDemo;
public class MyRunnable implements Runnable {
@Override
public void run() {
}
}
然后具体类似这样的格式
代码语言:javascript复制package demo.LambdaDemo;
public class MyRunnable implements Runnable {
@Override
public void run() {
}
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
Thread th = new Thread(my);
th.start();
}
}
还有一种是采用匿名内部类
代码语言:javascript复制 new Thread(new Runnable() {
@Override
public void run() {
System.out.println("");
}
}).start();
这样简化了操作。但是lambda比这个还要简化。
代码语言:javascript复制 new Thread(() -> {
System.out.println("...");
}).start();
对比上面的说明格式,你应该注意到这种格式。lambda里面有一个(),括号里面要求的是一种形式参数,但是你可以注意到我们这里英勇的接口没有使用形式参数,所以可以省略掉,然后剩下的就是你想做的事情了。所以就是这样的格式。
在这里,我们先体验一下,然后下面展开说明一些基本的使用具体实例。
实例一(抽象方法无参无返回值)
首先定义一个接口
代码语言:javascript复制package demo.LambdaDemo;
public interface Eatable {
void eat();
}
在测试类调用 我们可以去使用一个方法将接口参数传入
代码语言:javascript复制private static void useEatable(Eatable e)
{
e.eat();
}
然后你这样调用的话,其实还是没有具体实现。那么我们去具体实现一下。
采用匿名内部类
代码语言:javascript复制//匿名内部类实现
useEatable(new Eatable() {
@Override
public void eat() {
System.out.println("....");
}
});
对应采用的lambda表达式
代码语言:javascript复制 useEatable(()->{
System.out.println("...");
});
useEatable是我们定义的方法,我们的这个方法对应到接口Eatable接口,然后Eatable里面的这个方法并没有参数,我们就不需要传参,所以可以直接在{}里面做我们需要完成的事情。
实例二(抽线方法有参无返回值)
定义的接口类
代码语言:javascript复制package demo.LambdaDemo;
public interface Flayable {
void fly(String s);
}
可以注意到这个接口中的方法是有参的 还是在测试类中写一个方法
代码语言:javascript复制private static void useFlyable(Flayable f)
{
f.fly("。。。。。。。");
}
可以采用内名内部类对接口方法具体实现
代码语言:javascript复制 //匿名内部类
useFlyable(new Flayable() {
@Override
public void fly(String s) {
System.out.println(";;;;;;;;");
}
});
采用lambda表达式
代码语言:javascript复制 //lambda表达式
useFlyable((String s)->{
System.out.println(s);
System.out.println(".....");
});
实例三(抽象方法带参带返回值)
比如这样
代码语言:javascript复制package demo.LambdaDemo;
public interface Addable {
int add(int x,int y);
}
这是一个带参带返回值的抽象方法
然后匿名内部类实现
代码语言:javascript复制useAddable(new Addable() {
@Override
public int add(int x, int y) {
return x-y;
}
});
对的,这个方法具体实现在这里,具体的功能还是由我们自己具体实现来定。
lambda表达式
代码语言:javascript复制 useAddable((int x,int y)->{
return x y;
});
这是基本的写法。
lambda的表达式的简化操作
在特定条件下可以省略一些东西,变得更加简化。
1:参数类型可以省略(但是有多个参数的情况下,不能只省略一个)
如下,我们还是定义一个接口类
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo01;
public interface Addable {
int add(int x,int y);
}
然后测试类定义一个方法,当然在这里你也可以去简单实现
代码语言:javascript复制 private static void useAddable(Addable a)
{
int sum = a.add(10,20);
System.out.println(sum);
}
lambda常规
代码语言:javascript复制 useAddable((int x,int y)->{
return x y;
});
lambda简化
代码语言:javascript复制useAddable((x,y)->{
return x y;
});
注意这里省略的是参数类型,不是参数。
2:如果有且仅有一个参数,那么小括号可以省略
我们定义一个接口类
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo01;
public interface Flyable {
void fly(String s);
}
测试类定义方法
代码语言:javascript复制 private static void useFlyable(Flayable f)
{
f.fly("......");
}
private static void useAddable(Addable a)
{
int sum = a.add(10,20);
System.out.println(sum);
}
然后测试类操作 lambda常规
代码语言:javascript复制 useFlyable((String s)->{
System.out.println("....");
});
lambda简化
代码语言:javascript复制 useFlyable(s->{
System.out.println("....");
});
3:如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
代码语言:javascript复制useFlyable(s-> System.out.println("...."));
如果有return ,return也要省略掉
代码语言:javascript复制useAddable((x,y)->x y);
完整测试代码 接口
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo01;
public interface Addable {
int add(int x,int y);
}
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo01;
public interface Flyable {
void fly(String s);
}
测试类,部分代码已经注释。
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo01;
import demo.LambdaDemo.Flayable;
public class LambdaDemo {
public static void main(String[] args) {
// useAddable((int x,int y)->{
// return x y;
// });
//省略
// //1:参数类型可以省略(但是有多个参数的情况下,不能只省略一个)
// useAddable((x,y)->{
// return x y;
// });
// useFlyable((String s)->{
// System.out.println("....");
// });
// useFlyable((s)->{
// System.out.println("....");
// });
//2:如果有且仅有一个参数,那么小括号可以省略
// useFlyable(s->{
// System.out.println("....");
// });
// 3:如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
// useFlyable(s-> System.out.println("...."));
//如果有return ,return也要省略掉
useAddable((x,y)->x y);
}
private static void useFlyable(Flayable f)
{
f.fly("......");
}
private static void useAddable(Addable a)
{
int sum = a.add(10,20);
System.out.println(sum);
}
}
匿名内部类和lambda的使用区别
lambda的使用是比较严格的,要求有接口,还必须只有一个抽象方法。并且lambda必须是只能实现接口。在用法上,必须要有上下文环境。 这就说明的是,lambda表达式虽然可以省略某些内容,但是你必须提供上下文化境,让lambda可以推导出你是使用了什么接口,接口中的参数是什么等等。
简单的说,就是如果你没有定义接口,你直接使用lambda是不行的。接口或者接口中的方法可以认为是可以提供的环境,这样,省略的时候可以推导出来,下文的环境,就是基本你去实现的具体过程。
匿名内部类的要求比较宽泛。因为它的类型是都可以的。抽象类,接口,具体类都可以。在原理上,就是匿名内部类会在执行后生成一个新的字节码文件,但是lambda并不会,lambda是动态生成的。 具体测试
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo02.lambdaDemo03;
public interface Inter {
void show();
}
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo02.lambdaDemo03;
public class Student {
public void study()
{
System.out.println("....");
}
}
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo02.lambdaDemo03;
public abstract class Animal {
public abstract void method();
}
代码语言:javascript复制package demo.LambdaDemo.lambdaDemo02.lambdaDemo03;
public class LambdaDemo {
public static void main(String[] args) {
// //使用内名内部类
// useInter(new Inter() {
// @Override
// public void show() {
// System.out.println("接口");//接口调用
// }
// });
// useAnimal(new Animal() {
// @Override
// public void method() {
// System.out.println("抽象类");
// }
// });//可以调用方法参数为抽象类的形式
// useStudent(new Student(){
// public void study(){
// System.out.println("具体类");
// }
// });//也可以是具体类
//使用lambda只能是接口
useInter(()-> System.out.println("接口"));
//如果接口中有一个以上的抽象方法,那么就无法使用lambda表达式,只能用匿名内部类
}
private static void useStudent(Student s)
{
s.study();
}
private static void useAnimal(Animal a)
{
a.method();
}
private static void useInter(Inter i)
{
i.show();
}
}
基本的使用就是这些,具体的可以尝试使用了解。