- 浏览: 3552599 次
- 性别:
- 来自: 大连
博客专栏
-
使用Titanium Mo...
浏览量:38217
-
Cordova 3.x入门...
浏览量:607595
-
常用Java开源Libra...
浏览量:682776
-
搭建 CentOS 6 服...
浏览量:89532
-
Spring Boot 入...
浏览量:402142
-
基于Spring Secu...
浏览量:69760
-
MQTT入门
浏览量:91835
文章分类
最新评论
-
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 1574(一)分页类型 逻辑分页(客户端分页):从数据库将所有记录查询 ... -
JAXB实例入门
2017-06-09 10:17 1796JAXB(Java Architecture for XML ... -
Java Web项目中的Event
2017-06-05 09:42 1688(1)Servlet的事件和监听器 *** Servle ... -
关于Java SPI
2017-05-04 12:07 2050SPI:Service Provider Interface ... -
Jackson实例入门
2017-05-03 12:55 1722Jackson:Java平台的JSON解析器。 版本: ja ... -
为什么https被redirect成了http?
2016-11-14 09:35 7900全站HTTPS并不是配置证书CA,改改路径URL那么简单! ... -
简化Java代码
2016-10-09 11:25 1319样板代码Boilerplate Code的 ... -
Java Web Project based on Spring
2016-09-28 11:21 1045基于Spring开发Web项目的标配Library。 工具 ... -
Eclipse Scrapbook快速测试Java代码
2016-09-09 15:12 1336Scrapbook是Eclipse提供的特 ... -
Java爬取 百度图片&Google图片&Bing图片
2016-08-04 09:54 7631先看看抓取的结果。 抓关键字“美女”的百度图片: 抓关键字 ... -
学习Java容易混淆的一概念
2016-05-13 11:01 1702基础篇 (1)== vs equals() ... -
20年Java发展历程(1995-2015)
2015-03-25 21:58 2418Java语言作为现在最流行的编程语言之一,它已经经历了整整20 ... -
Java命令行选项解析之Commons-CLI & Args4J & JCommander
2014-11-27 12:09 22585熟悉Linux命令的都知道几乎所有程序都会提供一些命令行选项。 ... -
Java调用Native API之JNA
2014-11-10 12:09 7841Java调用C/C++的Native API一般采用JNI(J ... -
Java执行SSH/SCP之JSch
2014-08-27 17:17 11591JSch (Java Secure Channel)是纯Jav ... -
GC日志分析
2014-07-18 08:54 2876GC:Garbage Collection 垃圾回收 (1) ... -
Java元组类型之javatuples
2014-05-20 10:58 27085关于方法的返回值,经常需要返回2个值或多个值的一个序列,比如数 ... -
Java 8 之 反编译Lambda表达式(CFR)
2014-04-14 09:34 6591CFR(Class File Reader) - anoth ... -
Java 8 之 Optional类
2014-04-08 14:38 2991在Java中,null代表一个不存在的对象,如果对它进行操作就 ... -
Java 8 之 Lambda表达式
2014-04-01 09:14 16218Java 8历时2年8个月,这次升级是继Java 5之后对Ja ...
相关推荐
Java8 中引入了函数式接口的概念,函数式接口是一个只有一个抽象方法的接口,它可以使用 Lambda 表达式或方法引用来创建实例。函数式接口的出现使得 Java8 的编程模型更加灵活和强大。本文将对 Java8 函数式接口的...
Java 8引入了函数式接口的概念,这些接口只包含一个抽象方法,允许Lambda表达式的使用。Lambda表达式是一种简洁的表示匿名类的方法,它可以用于创建小型代码块,然后将其作为参数传递给方法或存储在变量中。类型推断...
这是Java 8为了实现函数式接口而引入的一个重要特性。 综上所述,Java 8的函数式编程特性为Java开发者提供了更优雅、高效的编码方式,尤其在处理集合数据时。通过掌握这些特性,开发者能够编写出更简洁、可读且易于...
Java 8 是一个重要的Java版本,它引入了函数式编程的概念,极大地扩展了语言的功能,使得Java开发者可以采用更加简洁、高效的方式来编写代码。Richard Warburton 的《java 8 函数式编程》是一本深入解析这一主题的...
Java 8提供了一些内置的函数式接口,如`Runnable`、`Callable`、`Comparator`等。开发者可以通过`@FunctionalInterface`进行检查,避免编译错误。 三、Lambda表达式 Lambda表达式是Java 8的一大亮点,它简化了对...
Java8其他相关学习博文Java8 Stream 流教学教程如何在Java8中风骚走位无意空指针异常Java8 发行篇(一) | 线程与执行器目录一、接口内允许添加默认实现的方法二、Lambda 表达式三、函数式接口 函数式接口四、方便的...
2. **函数式接口**:为支持lambda,Java 8引入了函数式接口的概念。这类接口只有一个抽象方法,例如`Runnable`和`Comparator`。`Supplier`、`Consumer`、`Function`和`Predicate`等新接口扩展了函数式编程的能力。 ...
2. **函数式接口**:为了支持lambda表达式,Java 8引入了函数式接口,如Runnable、Callable、Comparator等。这些接口只有一个抽象方法,可以被lambda表达式所代表。新添加的函数式接口有Supplier、Consumer、...
总结起来,Java8的Lambda表达式、函数式接口、默认方法和静态方法这些新特性,极大地改进了Java的编程模型,让代码更加简洁、易读和高效。通过熟练掌握这些特性,开发者可以编写出更加优雅和强大的程序,同时也为...
Java 8中提供了一些预定义的函数式接口,如`Predicate<T>`、`Function,R>`、`Consumer<T>`等。 - **示例**: ```java Predicate<String> predicate = (s) -> s.length() > 3; boolean result = predicate.test(...
- **函数式接口示例**:`java.lang.Runnable`接口就是一个典型的函数式接口,因为它只包含一个抽象方法`run()`。 - **@FunctionalInterface注解**:虽然可以通过检查接口是否仅包含一个抽象方法来确定其是否为函数...
本文将深入探讨Java 8 API中的核心概念,主要关注以下几个方面:Lambda表达式、函数式接口、Stream API、日期与时间API、方法引用来帮助开发者更高效地利用Java 8的功能。 1. **Lambda表达式**: Java 8引入了...
- Java 8引入了函数式接口的概念,这类接口只有一个抽象方法。常见的函数式接口有`java.util.function`包下的`Predicate`, `Function`, `Consumer`等。 - 函数式接口可以用于Lambda表达式,使得代码更加简洁,如在...
2. **函数式接口**:为了支持lambda表达式,Java 8引入了函数式接口的概念。这类接口只有一个抽象方法,比如`java.util.function.Function`、`java.util.concurrent.Callable`等。`Runnable`和`Callable`在Java 8...
综上所述,Java 8通过引入Lambda表达式、函数式接口、流API、方法引用、默认方法以及新的日期时间API,极大地增强了Java语言的能力,特别是在函数式编程领域。这些特性的加入,使得Java语言更加现代化,也使得Java...
2. **函数式接口**:为了支持lambda表达式,Java8引入了函数式接口的概念。这些接口只有一个抽象方法,比如`java.util.function.Function`,`java.util.function.Consumer`等,它们可以被lambda表达式实例化。 3. *...
总的来说,"java8中文api"这个文档涵盖了Java 8的所有新特性和重要API,包括Lambda表达式、Stream API、函数式接口、日期和时间API、Optional类以及并发改进等。无论你是初学者还是有经验的开发者,这个文档都将是你...
本文将全面介绍Java 8的几项核心新特性,包括Lambda表达式、函数式接口、方法引用与构造器引用、Stream API、接口中默认方法与静态方法、新的日期时间API以及通过这些特性所带来的代码减少、性能提升等。 ### ...
2. **函数式接口**:为了支持Lambda表达式,Java 8引入了函数式接口的概念。这些接口只有一个抽象方法,比如`Runnable`, `Callable`, `Consumer`, `Supplier`, `Predicate`, `Function`等。Lambda表达式可以隐式转换...
2. **函数式接口**:为了支持Lambda表达式,Java 8定义了函数式接口,即只有一个抽象方法的接口。例如,`java.util.function`包下提供了许多预定义的函数式接口,如`Predicate`、`Function`和`Consumer`等。 3. **...