Java8函数式接口/Lambda表达式/接口默认方法/接口静态方法/接口冲突方法重写/lambda表达式指定泛型类型等
一:函数式接口
1.函数式接口的概念就是此接口必须有且只能有一个抽象方法,可以通过@FunctionalInterface来显示规定(类似@Override),但是没有此注解的但是只有一个抽象方法的接口也是函数式接口;(接口也和类一样有包访问权限,但是内部的方法则默认是public)
@FunctionalInterface
public interface IFoo{
void print();
} // 就是一个最简单的函数式接口,但是如果再有个如void print2()抽象方法则这个接口不是函数式接口会在编译时便报错(因为有@FunctionalInterface)
2.接口里可以有静态方法(JDK8的新特性)
@FunctionalInterface
public interface IFoo{
void print();
static void sTest(){
System.out.println("msg");
}
}
注意,接口里的静态方法默认且只能是public的,就像接口里的字段默认且只能是public static的;调用时可以直接IFoo.sTest();
3.接口里也可以有default方法(JDK8新特性)
@FunctionalInterface
public interface IFoo{
void print();
default void sTest(){
System.out.println("msg");
}
}
与静态方法不同的是default方法本质上是实例方法,因此仍然需要创建IFoo的实现类对象才能调用此方法,如(new IFoo(){...}).sTest();是可以的但是IFoo.sTest()则错误
4.当一个接口成为了函数式接口后且也是以函数式接口来使用,它就类似C#里的委托,即接口和其里面的抽象方法是一一对应的,故泛型的声明要在接口名里而非抽象方法里
@FunctionalInterface
public interface IFoo<T extends Serializable>{
T print(T arg); // 写成<T> T print(T);对于将IFoo看成委托而言是错误的写法;注意<T extends B> T print。。在普通接口里也是可以的;
static void sTest(){
System.out.println("msg");
}
}
5.函数式接口对象和其Lambda表达式的关系
lambda表达式不会产生里面类的.class文件,而如new Predicate(){...}是会产生的,因此如果需要将lambda表达式转换为接口对象是需要强制转换的,如:((Predicate) o -> false).and(o -> false)
上面的(o -> false)是一个”函数对象“,它和new Predicate(){@Override test...}是不一样的,前者并没有产生Predicate的实现类,因此需要做一个强制类型转换将lambda表达式产生的结果转换为接口实现类对象;
6.将函数式接口当成委托使用
public interface Println<T>{
void println(T msg);
}
可以Println<String> println = System.out::println;来赋值;
7.实现多个接口但是又同名的default方法时必须重写/重定义该方法(如果是抽象方法则无所谓,当子类实现IC时实现print那么实际上即是实现IA的也是IB的不存在要重写两次的说法)
public interface IA{
default void print(){}
}
public interface IB{
default void print(){}
}
public interface IC extends IA, IB{
@Override
default void print(){IA.super.print();} // TODO 用于明确指定用IA的print,注意在JDK8以前由于没有default且只能继承一个类,因此只需要super.print()即可
}
8.lambda表达式的类型推导
如果是非泛型自然不需要,但是如果参数是泛型,但又无法隐式推导出时可以通过(String s) ->{..}来指定泛型的类型;
9.接口里可以都是default方法,此时这个接口可以直接new ITest{}就可以产生对象,但也可以重写default方法
10.可以在子接口里重写父接口的default方法令其在子接口里成为抽象方法;
11.lambda表达式和匿名内部类的区别
lambda表达式是很特殊的存在,它不会生成.class文件,而且它也不是接口的实现类的对象,应该这么理解IFoo foo = ()->true;是IFoo能够匹配右边的lambda表达式,而不是说这个正则表达式是一个IFoo的匿名实现类的对象;
注意上面存在一个隐式的转换即IFoo foo = (IFoo) ()->true;
12.将方法存储到“委托”里
ITest del = System::getenv; // 此时通过System.getenv方法实现了ITest的抽象方法;
del.method("string");注意,这里有几个重点,1)是ITest必须是函数式接口;2)ITest中的抽象方法名字任意且可以有泛型,但是必须能匹配System.getenv(..)这个方法的返回值和参数列表;3)del和C#的委托变量还是有些不一样的不能直接del(..)来调用,而是要del.method(..)来调用System.getenv方法;
n)还可以用ITest t = String::new;表示String的构造方法;那么t.func(..)方法的就是new String(..)而产生的对象;(构造方法某种程度上可以理解为类的静态方法)
n)IFoo2<String> ss = sbs::concat;,sbs是一个对象,因此ss.func(..)实际是是调用sbs.concat(..)方法
n)对于如果方法test是类A的实例方法,则ITest del = A::test;是错误的,IDE提示没有static的test方法,因为当del.func(..)调用时将不知道要调用哪个对象的test方法,因为test的调用必须依赖某个A对象;
补充:
1.lambda表达式里是可以将隐藏的this参数也作为参数的,比如接口里有唯一的抽象方法String test(String str);,那么lambda表达式里可以用Object::toString作为它的参数的(toString是实例方法obj.toString(),它显示里没有参数但是实际上有个this参数);
2.当存在方法:public <T> T execute(RedisCallback<T> action)时,用lambda表达式作为它的参数必须用(RedisCallback<Boolean>) connection -> {..}这种形式转换,这个特点是RedisCallback的T和execute的T进行了关联;
这里之所以必须强制转换,是因为java只允许从调用处开始往下一级一级的推算泛型,比如调用处是 a,然后它可以推算出a调用的b的泛型,然后再推算出b调用的c的泛型,而不能从a里先推算出c的泛型然后再网上递推出b处的泛型;
Java8函数式接口/Lambda表达式/接口默认方法/接口静态方法/接口冲突方法重写/lambda表达式指定泛型类型等的更多相关文章
- C#的静态方法和实例化方法的区别
C#的静态方法和实例化方法的区别 在大多数时候,我们写一个方法,会把方法区分为实例化方法和静态方法.而当被问到静态方法和实例化方法的区别的时候,我在写这篇文章的前10分钟,或许我会回答:"静 ...
- [二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口
函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type use ...
- java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口
函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...
- Java8函数式接口和Lambda表达式
两者关系: Lambda表达式就是函数式接口(FunctionalInterface)实现的快捷方式,它相当于函数式接口实现的实例,因为在方法中可以使用Object作为参数,所以把Lambda表达式作 ...
- 30分钟入门Java8之默认方法和静态接口方法
30分钟入门Java8之默认方法和静态接口方法 前言 上一篇文章30分钟入门Java8之lambda表达式,我们学习了lambda表达式.现在继续Java8新语言特性的学习,今天,我们要学习的是默认方 ...
- Java8之默认方法和静态接口方法
前言 上一篇文章30分钟入门Java8之lambda表达式,我们学习了lambda表达式.现在继续Java8新语言特性的学习,今天,我们要学习的是默认方法和静态接口方法. 这一Java8的新语言特性, ...
- jdk8系列一、jdk8 Lamda表达式语法、接口的默认方法和静态方法、supplier用法
一.简介 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和JVM等方面的十多个新特性. 在本文中我们将学习这些新特性,并用实际 ...
- Java8新特性之四:接口默认方法和静态方法
在JDK1.8以前,接口(interface)没有提供任何具体的实现,在<JAVA编程思想>中是这样描述的:"interface这个关键字产生了一个完全抽象的类,它根本就没有提供 ...
- java8之lambda表达式(默认方法)
[推荐]2019 Java 开发者跳槽指南.pdf(吐血整理)>>> 许多开发语言都将函数表达式集成到了其集合库中.这样比循环方式所需的代码更少,并且更加容易理解.以下面的循环为例: ...
随机推荐
- js 定时执行
代码: 格式例子: setInterval(方法名,1000*60); setInterval("方法名()",1000*60); setInterval(function () ...
- swift - 画图截取图片 - 保存相册
1.图片截取 func test(addView:UIView) -> UIImage?{ UIGraphicsBeginImageContextWithOptions(CGSize(width ...
- OnActionExecuting验证用户登录
代码 using Common; using Service; using Service.IService; using System; using System.Collections.Gener ...
- Vue-CLI3.x 高版本覆盖低版本Vue-CLI2.x 解决方法
因为Vue-cli 3 和旧版使用了相同的vue命令,所以Vue CLI 2(vue-cli) 被覆盖了.如果你任然需要旧版本的 vue init 功能 ,你可以全局安装一个交接工具: npm ins ...
- 文章如何做伪原创 SEO大神教你几招做"原创"网站文章的心得
想要创作出好的文章并被百度所喜欢,就非常需要SEO的优化能力,以及要对文章进行塬创或伪塬创,那么,如何做伪塬创文章?以及如何做好塬创网站文章呢?对此,本文小编就为大家带来了几招做"塬创&qu ...
- go 语言实现一个简单的 web 服务器
学习Go语言的一些感受,不一定准确. 假如发生战争,JAVA一般都是充当航母战斗群的角色.一旦出动,就是护卫舰.巡洋舰.航母舰载机.预警机.电子战飞机.潜艇等等浩浩荡荡,杀将过去.(JVM,数十个JA ...
- git 远程仓库与本地项目关联
在git 中创建一个项目或仓库如起名blog,生成README.md文件,在本地创建一个项目名为blog ,blog里面是代码,此时执行 git remote add origin <ssh协 ...
- 开源项目CircleImageView
1.在自己MainActivity所在包下创建CircleImageView.class文件 package 自己包名; import android.content.Context; import ...
- iOS.PrototypeTools
1. iPhone/iPad 原型工具 http://giveabrief.com/ 2. proto.io https://proto.io/ 3. Origami http://facebook. ...
- python实现文件下载图片视频
最近在学习爬虫,在爬取网站时很多时候是需要将图片或视频下载到本地 今天就来说说如何使用urllib将图片保存到本地 以下代码均为win7 python3.6.* 方法一(使用下载函数保存) from ...