Lambda 表达式(2)
接口的组成更新
接口的组成
- 常量
接口中常量默认是 public static final
这些是可以省略的
-
抽象方法
接口中方法默认是
public abstract
这些是可以省略的 -
默认方法(java8)
-
静态方法(java8)
-
私有方法(java9)
默认方法(java8)
在出现默认方法之前,实现类必须实现接口的每一个方法,那么如果一个接口的实现类很多,但是有的实现类并不需要实现某些方法的时候,静态方法就有了用处。
例如:定义接口并且有两个普通方法和一个默认方法。
默认方法必须加default 关键字
public interface InterTest {
void test();
void test1();
default void test2(){
//todo 此处写接口默认的方法,如果实现类不重写的话,会默认走此内容
}
}
实现类:
两个普通的方法,实现类中必须实现,但是默认方法可以选择实现
public class InterTestImpl1 implements InterTest {
@Override
public void test() {
}
@Override
public void test1() {
}
}
静态方法(java8)
静态方法格式:在方法前加static
关键字
注意事项:静态方法只能通过接口名称调用,不能通过实现类名或者对象名调用。
例子:
public interface InterTest {
void test();
void test1();
static void test2(){
System.out.print("start");
}
}
实现类 中无法重写静态方法
public class InterTestImpl1 implements InterTest {
@Override
public void test() {
}
@Override
public void test1() {
}
}
调用的时候只能通过接口名称进行调用
public class LambdaTest {
public static void main(String[] args) {
InterTest test = new InterTestImpl1();
// 普通方法调用
test.test();
// 静态方法调用
InterTest.test2();
}
}
私有方法(java9)
在java8中有了默认方法和静态方法,如果在在一个接口中有两个默认方法或者静态方法的时候,而且两个方法中有公用的代码块,便会出现代码冗余;
例如:
public interface InterTest {
static void test2(){
System.out.print("我是test2");
System.out.print("早上起床");
System.out.print("洗漱");
System.out.print("吃饭");
System.out.print("出门");
}
static void test3(){
System.out.print("我是test3");
System.out.print("早上起床");
System.out.print("洗漱");
System.out.print("吃饭");
System.out.print("出门");
}
}
如上代码出现了很多代码冗余,但是这些代码是接口的静态方法,并不需要在实现中使用,那么私有方法的出现解决了此问题;
public interface InterTest {
default void test1(){
System.out.print("我是test1");
test2();
}
static void test2(){
System.out.print("我是test2");
test4();
}
static void test3(){
System.out.print("我是test3");
test4();
}
private static void test4(){
System.out.print("早上起床");
System.out.print("洗漱");
System.out.print("吃饭");
System.out.print("出门");
}
}
接口的私有方法和平时的私有方法的声明方式是一样的。并且发现,默认方法是可以调用静态方法的,但是静态方法不能调用默认方法。
方法引用
个人感觉方法引用比较难理解。。。。
如果我们在Lambda 中想要写的代码块已经存在,那么就没有必要再重复写了,那么在这种情况下如何引用呢?
例子:
public interface ILambdaTest {
void start(String s);
}
调用此接口
public class LambdaTest {
public static void main(String[] args) {
LamTest(s->{
show(s);
});
}
public static void LamTest(ILambdaTest test){
test.start("hello");
}
public static void show(String s){
System.out.println("你好"+s);
System.out.println("我是很复杂的代码1");
System.out.println("我是很复杂的代码2");
}
}
如此调用是之前用Lambda的方式调用,现在我们可以方法引用
public class LambdaTest {
public static void main(String[] args) {
LamTest(LambdaTest::show);
}
public static void LamTest(ILambdaTest test){
test.start("hello");
}
public static void show(String s){
System.out.println("你好"+s);
System.out.println("我是很复杂的代码1");
System.out.println("我是很复杂的代码2");
}
}
或者如下写法
public class LambdaTest {
public static void main(String[] args) {
LamTest(s->System.out.println(s));
// 两行代码的结果是一样的
LamTest(System.out::println);
}
public static void LamTest(ILambdaTest test){
test.start("hello");
}
}
此处方法引用,从s->{}
到LambdaTest:show
这个方法的引用意思是重写接口的实现,并且把入参传入到show(String s) 方法的s中,只不过很多操作都省略了,
一般情况下, 可推导的内容就是可以省略的。
说明:
::
该符号是引用运算符,而它所在的表达式是方法的应用
例如最后的写法中:
-
Lambda中写法
LamTest(s->System.out.println(s));
此写法是参数s传到Sysout.out.println中进行打印。 -
方法引用写法
LamTest(System.out::println);
方法引用的写法更加简洁
推导和省略
- 如果使用了Lambda,那么可根据“可推导就可以省略”的原则,无需要指定参数类型,也不用指定重载形式。
- 如果是方法引用,也可以根据上下文进行推导。
- 方法应用是Lambda的孪生兄弟。
Lambda支持的方法引用
常见的引用方式:
- 引用类方法
- 引用对象的实例方法
- 引用类的实例方法
- 引用构造器
引用类方法
应用类的静态方法
格式: 类名::静态方法名
例如:
定义接口
public interface ILambdaTest {
Integer start(String s);
}
public class LambdaTest {
public static void main(String[] args) {
//Lambda 表达式是调用
LamTest(s->Integer.parseInt(s));
// 方法引用进行调用
LamTest(Integer::parseInt);
// 两个方法调用的接口是一样的
}
public static void LamTest(ILambdaTest test){
Integer i = test.start("123");
System.out.println(i);
}
}
引用对象的方法
格式: 对象::成员方法
例子:
定义接口
public interface ILambdaTest {
Integer start(String s);
}
public class LambdaTest {
public static void main(String[] args) {
// Lambda 表达式调用
LamTest(s->Integer.parseInt(s));
// 方法引用方式调用
LambdaTest test = new LambdaTest();
LamTest(test::show);
}
private Integer show(String s){
return Integer.parseInt(s);
}
public static void LamTest(ILambdaTest test){
Integer i = test.start("123");
System.out.println(i);
}
}
引用类的实例方法
例如:
public interface ILambdaTest {
Integer start(LambdaTest s,String str);
}
如上接口,接口中的参数存在一个类的实例;
如上该如何调用? 写法如下:
public class LambdaTest {
public static void main(String[] args) {
// Lambda 表达式调用
LamTest((s,y)->s.show(y));
// 方法引用方式调用
LamTest(LambdaTest::show);
// 说明: 如果是类的实例方法调用的话,第一个参数是调用者
// 剩下的是传递给对应方法作为参数
// 如上说明LambdaTest:show
// 表示:s调用show方法,并且传递给的参数是y;
// s 就是LamTest中的new LambdaTest()
// y 就是“123”
}
private Integer show(String s){
return Integer.parseInt(s);
}
public static void LamTest(ILambdaTest test){
Integer i = test.start(new LambdaTest(),"123");
System.out.println(i);
}
}
引用构造器
Lambda表达式被构造器替代的时候,它的所有形参全部会传递给构造器作为参数
例子:
public class UserInfo {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserInfo(Long id, String name) {
this.id = id;
this.name = name;
}
}
创建接口
public interface ILambdaTest {
UserInfo start(Long id,String name);
}
public class LambdaTest {
public static void main(String[] args) {
// Lambda 表达式调用
LamTest((s,y)->new UserInfo(s,y));
// 方法引用方式调用
LamTest(UserInfo::new);
//Lambda表达式被构造器替代的时候,它的所有形参全部会传递给构造器作为参数
}
private Integer show(String s){
return Integer.parseInt(s);
}
public static void LamTest(ILambdaTest test){
UserInfo userInfo = test.start(1L,"123");
}
}