- 浏览: 3515291 次
- 性别:
- 来自: 大连
博客专栏
-
使用Titanium Mo...
浏览量:37505
-
Cordova 3.x入门...
浏览量:604415
-
常用Java开源Libra...
浏览量:678191
-
搭建 CentOS 6 服...
浏览量:87346
-
Spring Boot 入...
浏览量:399876
-
基于Spring Secu...
浏览量:69090
-
MQTT入门
浏览量:90521
文章分类
最新评论
-
afateg:
阿里云的图是怎么画出来的?用什么工具?
各云服务平台的架构图 -
cbn_1992:
博主,采用jdbctoken也就是数据库形式之后,反复点击获取 ...
Spring Security OAuth2 Provider 之 数据库存储 -
ipodao:
写的很是清楚了,我找到一份中文协议:https://mcxia ...
MQTT入门(6)- 主题Topics -
Cavani_cc:
还行
MQTT入门(6)- 主题Topics -
fexiong:
博主,能否提供完整源码用于学习?邮箱:2199611997@q ...
TensorFlow 之 构建人物识别系统
默认方法(Default Methods)
在Java的interface中一直只是包含方法的定义不能有实现,而且Java也不支持多继承。参考Why Multiple Inheritance is Not Supported in Java。Java 8开始提供在interface中可以有方法的实现,这个特性叫默认方法“Default Methods”。如此以来,interface有了方法实现,Java即可实现多继承,Java一贯提倡不支持多继承,为什么这次妥协了呢?
因为interface太过依赖于他们的实现类了,要往interface中添加一个方法就必须修改所有它的实现类。Java8的Lambda表达式基本上都是一个函数式接口,为了实现lambda表达式并无缝支持Lambda表达式,Java核心的一些类就需要修改。但是像java.util.List这样的接口不仅仅在JDK中被实现,还有其他很多第三方库在实现,稍微的改动都存在兼容性问题。试想一下如果没有默认方法的话,是不是要修改所有集合类的实现啊。
所以,在不破坏继承关系的前提下,引入“虚拟扩展方法”的概念,在接口中添加默认方法的实现,这也是很聪明的,虽然Java语言在被设计的时候一直强调不支持多继承,看来这次也是没有办法的了,Java也变得越来越像C#了。
简单试用:
多重继承:
调用继承过来的默认方法重名的时候:
抽象方法和默认方法重名的时候:
默认方法再抽象化:
多重继承相同的默认方法必须覆写:
父类优先于接口:
默认方法不支持final和synchronized修饰符,只支持public, abstract, default, static, strictfp。
除过以前的那些区别外,带有默认方法的interface和抽象类的区别:
默认方法不能覆盖 equals, hashCode, toString 方法!!!
原因可以参考Brian Goetz给出的回答:Allow default methods to override Object's methods
http://viralpatel.net/blogs/java-8-default-methods-tutorial/
http://zeroturnaround.com/rebellabs/java-8-explained-default-methods/
函数式接口(Functional Interfaces)
函数式接口就是只包含一个抽象方法的接口。比如Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。使用注解 @FunctionalInterface 可以显示指明一个接口是函数式接口,但如果接口中只定义了一个抽象方法,通常不用自己写这个注解,编译器会自动识别它就是函数式接口。因为默认方法不是抽象的,所以函数接口里还可以定义任意多的默认方法。实质就是 C# 的委托(delegate)。
定义
实现
如果接口有多个抽象方法,会提示“The target type of this expression must be a functional interface”。
Comparator接口里面虽然声明了两个方法,但它是函数接口。因为equals方法是Object的,不影响它依然是个函数接口。
Java 8在java.util.function中定义了很多常用的函数类型接口。
分类
最常用的:
对于int/long/double类型还有特别的封装。
方法引用(Method References)
就是已存在方法的函数式接口,可以看做是调用一个方法的lambda简化。
比如:
lambda表达式: (Apple a) -> a.getWeight()
方法引用:Apple::getWeight
都代表了Apple类中的getWeight()方法
可以看得出这是lambda调用单个方法的语法糖。
其他的还有:
1个参数1个返回值:Math::pow 等价于 (x, y) -> Math.pow(x, y)
只有参数: System.out::println 等价于 x -> System.out.println(x)
2个参数1个返回值:String::compareToIgnoreCase 等价于 (x, y) -> x.compareToIgnoreCase(y)
等等。
4种类型
(1)构造函数
ClassName::new 比如:Integer::new
数组的构造函数:String[]::new
(2)静态方法
ClassName::staticMethodName 比如:String::valueOf
(3)实例方法(类型)
ClassName::instanceMethodName 比如:String::length
(4)实例方法(对象)
object::instanceMethodName 比如:obj:getValue
***在类的内部可以使用this引用当前类的方法,或者使用super引用父类的方法。比如:this::startsWith
***类的静态成员变量的方法也可以引用。ClassA.StaticField::methodName 比如: System.out::println
***抛出异常的方法不能用于方法引用
在Java的interface中一直只是包含方法的定义不能有实现,而且Java也不支持多继承。参考Why Multiple Inheritance is Not Supported in Java。Java 8开始提供在interface中可以有方法的实现,这个特性叫默认方法“Default Methods”。如此以来,interface有了方法实现,Java即可实现多继承,Java一贯提倡不支持多继承,为什么这次妥协了呢?
因为interface太过依赖于他们的实现类了,要往interface中添加一个方法就必须修改所有它的实现类。Java8的Lambda表达式基本上都是一个函数式接口,为了实现lambda表达式并无缝支持Lambda表达式,Java核心的一些类就需要修改。但是像java.util.List这样的接口不仅仅在JDK中被实现,还有其他很多第三方库在实现,稍微的改动都存在兼容性问题。试想一下如果没有默认方法的话,是不是要修改所有集合类的实现啊。
List<?> list = … list.forEach(…);
所以,在不破坏继承关系的前提下,引入“虚拟扩展方法”的概念,在接口中添加默认方法的实现,这也是很聪明的,虽然Java语言在被设计的时候一直强调不支持多继承,看来这次也是没有办法的了,Java也变得越来越像C#了。
简单试用:
interface Person { // adds a java 8 default method default void sayHello() { System.out.println("Hello"); } } class Sam implements Person { } new Sam().sayHello();
多重继承:
interface Person { // adds a java 8 default method default void sayHello() { System.out.println("Hello"); } } interface Male { default void sayBye() { System.out.println("Bye"); } } class Sam2 implements Person, Male { } new Sam2().sayHello(); new Sam2().sayBye();
调用继承过来的默认方法重名的时候:
interface Person { // adds a java 8 default method default void sayHello() { System.out.println("Hello"); } } interface Male { default void sayHello() { System.out.println("Hi"); } } class Sam2 implements Person, Male { // override the sayHello to resolve ambiguity public void sayHello() { Male.super.sayHello(); } }
抽象方法和默认方法重名的时候:
interface Q1 { abstract void m(); } interface Q2 { default void m() { System.out.println("m@Q2"); } } class Sam3 implements Q1, Q2 { @Override public void m() { System.out.println("m@Sam3"); } } new Sam3().m(); // m@Sam3
默认方法再抽象化:
public class D1 { public static void main(String[] args) { // 默认方法再抽象化 new D1().test(); // FOO2 } interface Foo { default void print() { System.out.println("FOO"); } } interface Foo2 extends Foo { @Override void print(); } public void test() { Foo2 foo = new Foo2() { @Override public void print() { System.out.println("FOO2"); } }; foo.print(); } }
多重继承相同的默认方法必须覆写:
public class D2 { public static void main(String[] args) { // 多重继承相同的默认方法必须覆写 new D2().new FooBar().print(); // FOOBAR } interface Foo { default void print() { System.out.println("FOO"); } } interface Bar { default void print() { System.out.println("BAR"); } } class FooBar implements Foo, Bar { @Override public void print() { System.out.println("FOOBAR"); } } }
父类优先于接口:
public class D3 { public static void main(String[] args) { // 父类优先于接口 new D3().test(); // BAR } interface Foo { default void print() { System.out.println("FOO"); } } class Bar { public void print() { System.out.println("BAR"); } } class FooBar extends Bar implements Foo { } public void test() { FooBar foobar = new FooBar(); foobar.print(); } }
默认方法不支持final和synchronized修饰符,只支持public, abstract, default, static, strictfp。
interface NoTrait { default final void noFinal() { // ^^^^^ modifier final not allowed System.out.println("noFinal"); } default synchronized void noSynchronized() { // ^^^^^^^^^^^^ modifier synchronized not allowed System.out.println("noSynchronized"); } }
除过以前的那些区别外,带有默认方法的interface和抽象类的区别:
- 抽象类是有个状态的,它可以有构造函数和成员变量
- 抽象类不能用于lambda表达式中
默认方法不能覆盖 equals, hashCode, toString 方法!!!
原因可以参考Brian Goetz给出的回答:Allow default methods to override Object's methods
http://viralpatel.net/blogs/java-8-default-methods-tutorial/
http://zeroturnaround.com/rebellabs/java-8-explained-default-methods/
函数式接口(Functional Interfaces)
函数式接口就是只包含一个抽象方法的接口。比如Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。使用注解 @FunctionalInterface 可以显示指明一个接口是函数式接口,但如果接口中只定义了一个抽象方法,通常不用自己写这个注解,编译器会自动识别它就是函数式接口。因为默认方法不是抽象的,所以函数接口里还可以定义任意多的默认方法。实质就是 C# 的委托(delegate)。
定义
interface MyFi1 { public abstract void run(); } @FunctionalInterface interface MyFi2 { public abstract void run(); } @FunctionalInterface interface MyFi3 { public abstract void run(); default void tripleRun(){ run();run();run(); } }
实现
// 匿名类实现 new MyFi1() { @Override public void run() { System.out.println("Anonymous Inner class"); } }.run();
// lambda表达式实现只需要提供形式参数和方法体。 // 函数式接口只有一个抽象方法,编译器能自动推断方法。 MyFi1 dbl = () -> System.out.println("Lambda Expression"); dbl.run();
如果接口有多个抽象方法,会提示“The target type of this expression must be a functional interface”。
public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
Comparator接口里面虽然声明了两个方法,但它是函数接口。因为equals方法是Object的,不影响它依然是个函数接口。
Java 8在java.util.function中定义了很多常用的函数类型接口。
分类
- 函数:Function / BiFunction T -> R
- 运算:UnaryOperator / BinaryOperator T -> T 或 (T, T) -> T
- 预言:Predicate / BiPredicate
- 生产者:Supplier 返回T
- 消费者:Consumer / BiConsumer 只有一个参数
最常用的:
- 1个参数一个返回值:Function<paramType, returnType>
- 1个参数没有返回值:Consumer<paramType>
- 没有参数一个返回值:Supplier<returnType>
对于int/long/double类型还有特别的封装。
Function<String, Integer> len = s -> s.length(); System.out.println( len.apply("abc")); Predicate<String> tooLong = s -> s.length() > 10; if(tooLong.test("rensanning@gmail.com")){ System.out.println("long"); } Consumer<String> print = s -> System.out.println( s ); print.accept("foobar"); Supplier<String> sup = () -> String.join("", Collections.nCopies(100, "a")); System.out.println( sup.get() );
方法引用(Method References)
就是已存在方法的函数式接口,可以看做是调用一个方法的lambda简化。
比如:
lambda表达式: (Apple a) -> a.getWeight()
方法引用:Apple::getWeight
都代表了Apple类中的getWeight()方法
可以看得出这是lambda调用单个方法的语法糖。
其他的还有:
1个参数1个返回值:Math::pow 等价于 (x, y) -> Math.pow(x, y)
只有参数: System.out::println 等价于 x -> System.out.println(x)
2个参数1个返回值:String::compareToIgnoreCase 等价于 (x, y) -> x.compareToIgnoreCase(y)
等等。
4种类型
(1)构造函数
ClassName::new 比如:Integer::new
Function<String, Integer> cFunc = Integer::new; System.out.println(cFunc.apply("1")); // 1
数组的构造函数:String[]::new
(2)静态方法
ClassName::staticMethodName 比如:String::valueOf
Function<Integer, String> sFunc = String::valueOf; System.out.println(sFunc.apply(123)); // 123
(3)实例方法(类型)
ClassName::instanceMethodName 比如:String::length
Function<String, Integer> func1 = String::length; System.out.println(func1.apply("Java 8")); // 6
(4)实例方法(对象)
object::instanceMethodName 比如:obj:getValue
class Something { String startsWith(String s) { return String.valueOf(s.charAt(0)); } } Something something = new Something(); Function<String, String> converter = something::startsWith; System.out.println(converter.apply("Java")); // "J"
***在类的内部可以使用this引用当前类的方法,或者使用super引用父类的方法。比如:this::startsWith
class Base { String endWith(String s) { return String.valueOf(s.charAt(s.length() - 1)); } } class Something extends Base { String startsWith(String s) { return String.valueOf(s.charAt(0)); } void test() { Function<String, String> converter1 = this::startsWith; System.out.println(converter1.apply("abcdefg")); // a Function<String, String> converter2 = super::endWith; System.out.println(converter2.apply("abcdefg")); // g } }
***类的静态成员变量的方法也可以引用。ClassA.StaticField::methodName 比如: System.out::println
class SomeElse { public static final Something st = new Something(); } Function<String, String> p = SomeElse.st::startsWith; System.out.println(p.apply("123")); // 1
***抛出异常的方法不能用于方法引用
List<Path> paths = null; // Unhandled exception type IOException paths.forEach(Files::delete); //NG paths.forEach(path -> { try { Files.delete(path); } catch (IOException ex) { // 例外処理 } });
发表评论
-
Web API分页
2018-11-13 13:38 1507(一)分页类型 逻辑分页(客户端分页):从数据库将所有记录查询 ... -
JAXB实例入门
2017-06-09 10:17 1707JAXB(Java Architecture for XML ... -
Java Web项目中的Event
2017-06-05 09:42 1618(1)Servlet的事件和监听器 *** Servle ... -
关于Java SPI
2017-05-04 12:07 1993SPI:Service Provider Interface ... -
Jackson实例入门
2017-05-03 12:55 1639Jackson:Java平台的JSON解析器。 版本: ja ... -
为什么https被redirect成了http?
2016-11-14 09:35 7641全站HTTPS并不是配置证书CA,改改路径URL那么简单! ... -
简化Java代码
2016-10-09 11:25 1251样板代码Boilerplate Code的 ... -
Java Web Project based on Spring
2016-09-28 11:21 988基于Spring开发Web项目的标配Library。 工具 ... -
Eclipse Scrapbook快速测试Java代码
2016-09-09 15:12 1281Scrapbook是Eclipse提供的特 ... -
Java爬取 百度图片&Google图片&Bing图片
2016-08-04 09:54 7460先看看抓取的结果。 抓关键字“美女”的百度图片: 抓关键字 ... -
学习Java容易混淆的一概念
2016-05-13 11:01 1611基础篇 (1)== vs equals() ... -
20年Java发展历程(1995-2015)
2015-03-25 21:58 2278Java语言作为现在最流行的编程语言之一,它已经经历了整整20 ... -
Java命令行选项解析之Commons-CLI & Args4J & JCommander
2014-11-27 12:09 22388熟悉Linux命令的都知道几乎所有程序都会提供一些命令行选项。 ... -
Java调用Native API之JNA
2014-11-10 12:09 7716Java调用C/C++的Native API一般采用JNI(J ... -
Java执行SSH/SCP之JSch
2014-08-27 17:17 11429JSch (Java Secure Channel)是纯Jav ... -
GC日志分析
2014-07-18 08:54 2825GC:Garbage Collection 垃圾回收 (1) ... -
Java元组类型之javatuples
2014-05-20 10:58 26920关于方法的返回值,经常需要返回2个值或多个值的一个序列,比如数 ... -
Java 8 之 反编译Lambda表达式(CFR)
2014-04-14 09:34 6478CFR(Class File Reader) - anoth ... -
Java 8 之 Optional类
2014-04-08 14:38 2935在Java中,null代表一个不存在的对象,如果对它进行操作就 ... -
Java 8 之 Lambda表达式
2014-04-01 09:14 16126Java 8历时2年8个月,这次升级是继Java 5之后对Ja ...
相关推荐
Java 8 简明教程 Java 8 Tutorial中文版 “Java并没有没落,人们很快就会发现这一点” 欢迎阅读我编写的Java 8介绍。本教程将带领你一步一步地认识...了解,例如:流控制,函数式接口,map扩展和新的时间日期API等等。
函数式编程中中新加了一些概念:Lambda表达式、函数式接口、函数引用、默认方法、Optional类等;Stream中提供了一些流式处理集合的方法,并提供了一些归约、划分等类的方法;日期中添加了ZoneDateTime、DataFormat等...
尚硅谷_Java8新特性_四大内置核心函数式接口 ·06. 尚硅谷_Java8新特性_方法引用与构造器引用 ·07. 尚硅谷_Java8新特性_创建 Stream ·08. 尚硅谷_Java8新特性_Stream_筛选与切片 ·09. 尚硅谷_Java8新特性_Stream...
函数式接口结合Lambda表达式和方法引用,使得开发人员能够将方法作为参数传递,提高了代码的灵活性和复用性。 3. 流式API(Stream API):JDK 1.8中引入了Stream API,它提供了一种处理集合数据的流式操作方式,...
该书由 Mario Fusco、Alan Mycroft 和 Raoul-Gabriel Urma 合著,旨在帮助读者深入了解 Java 8,并掌握其中的关键...其他新特性: 简要介绍 Java 8 中引入的其他新特性,如接口的默认方法、方法引用、Optional 类型等。
4、函数式接口使用:学习如何使用Lambda表达式与Java中的函数式接口进行交互,包括传递函数、使用函数式接口的默认方法和方法引用。 本源码资源旨在帮助用户掌握以下几个方面: 1、Lambda表达式概述:了解Lambda...
Java8 简明教程.pdf 本教程将带领你一步一步地认识这门语言的新特性。通过简单明了的代码 示例,你将会学习到如何使用...你还将对最新推出的API有一定的了解,例如:流控制,函数式接口,map扩展和新的时间日期API等等
Java 8新特性PDF课件,介绍了Lambda表达式,函数式接口,方法引用,Stream API ,接口中的默认方法和静态方法,新日期时间API, Option接口等特性
如果一个接口只有一个抽象方法(其他的方法比如默认方法或与java.lang.Object类相同的方法可以有多个),那么该接口就是一个函数式接口 如果我们在某个接口上声明了FunctionInterface注解,那么编译器会按照函数式接口...
本文档将Java8的新特新逐一添加,比如如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API上的改进,比如流,函数式接口,Map以及全新的日期API。祝你Java技术更上一层楼!
2、函数式接口 3、方法引用和构造引用 4、Stream API 5、接口中的默认方法和静态方法 6、新时间日期API 7、OPtional 8、其他特性 二、java8(JDK1.8)新特性简介 1、速度快; 2、代码少、简介(新增特性:...
即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是依然使用匿名内部类解决。 本系列课程从Lambda表达式、方法的引用、Stream API三处着手...
自己整理的java8新特性及demo ...5. 四大函数式接口 8 6. Stream 11 7. Map接口的新方法: 19 8. 并行流与串行流 20 9. Optional容器类 23 10. 接口中默认的方法和静态方法 26 11. 日期 26
Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。 Date Time API − 加强对日期与时间的处理。 Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空...
java8流源码Java8 参考 这是我自己对 java 8 中的新结构和特性的引用 接口和 Lambda 表达式 ...函数式接口是只包含一个抽象方法的接口。 @FunctionalInterface interface IFuntionalInterface <R
1.3 函数式接口 6 1.4 方法引用 8 1.5 构造器引用 10 1.6 变量作用域 10 1.7 默认方法 14 1.8 接口中的静态方法 17 练习 18 第2章 Stream API 20 2.1 从迭代器到Stream操作 22 2.2 创建Stream 23 2.3 filter、map和...
Java8 十大新特性详解 接口的默认方法详解、Lambda 表达式详解、函数式接口详解、方法与构造函数引用详解、Lambda 作用域详解、访问对象字段与静态变量详解、访问接口的默认方法详解
接口:从jdk8开始,接口可以定义为函数式接口,并新增了两种类型的方法,【静态方法和默认方法】打破了接口以前的定义“实现这个接口就一定要实现接口中的所有方法”,具体请看示例。 Stream API:新添加的Stream ...