一、缺省方法
首先看一段用Java 8写的代码:
//create a list, and add 3 elements List<String> l = new ArrayList<String>() { { add("Hello"); add("World"); add("Peace"); } }; //print element in l one by one l.forEach(System.out::println);
首先创建一个 List 对象,并添加了三个元素到其中,然后调用 List 的 forEach 方法将其中的元素一个一个打印出来。
但是我们都知道 List 是一个接口,其中没有 forEach 方法,而如果直接在 List 接口中添加新的方法定义,则会破坏向下兼容性,因为以前的程序在新的Java环境里因缺少对该方法的实现而报错。Java 8中解决这一问题的手段就是使用缺省方法。
缺省方法是在接口中定义方法实现的一种方式,并且保证所有已经存在的子类的兼容性,所以实现了接口的类默认都拥有在接口中定义的缺省方法,这有点像一个抽象类。当一个子类中没有覆盖缺省方法时,则对子类的该方法的调用将调用接口中的实现。缺省方法的声明方式如下:
public interface DefaultInterface { default int getValue(){ return 1; } }
只需要在方法前加关键字 default 即可。
缺省方法提供了一种在不破坏现在接口实现的情况下,给接口添加新的功能的途径。查看集合类的源码就会发现Java 8的集合类接口中添加了很多缺省的方法实现,用于提供对集合的共同的操作,如上所示的 forEach 方法。
一个类可以实现多个接口,如果其中有多于一个接口有相同的缺省方法时,则子类需要定义自己的实现,否则会报编译错误:
interface A{ default String name(){ return "A"; } } interface B{ default String name(){ return "B"; } } class C implements A, B{ public String name(){ return A.super.name(); } }
二、forEach() 方法
forEach() 方法的源码如下:
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
这里 this 对象就是 List 对象本身,t 就是 List 中的遍历的元素。写在我们熟悉的方式就是:
for(String s: l){ action.accept(s); }
三、java.util.function.Consumer 接口
看上面 forEach() 方法参数,需要的是一个 Consumer 对象,这里我们传入的是一个 System.out::println 。 Consumer 是新增的函数编程接口中的一个,看它的介绍:
Represents an operation that accepts a single input argument and returns no result.
而双冒号 :: 操作符也是新增的一个操作符,表示一个函数引用。结合起来理解应该就是:一个类的任何一个方法,如果它只有一个参数,并且没有返回值,则在需要Consumer参数的地方都可以把此方法作为函数引用传入。
可以作个实验。先定义以下类:
class TestConsumer{ public static TestConsumer INSTANCE = new TestConsumer(); public void sayHello(String s){ System.out.println("Hello "+s); } }
然后替换 System.out::println 为 TestConsumer.INSTANCE::sayHello,如下:
//create a list, and add 3 elements List<String> l = new ArrayList<String>() { { add("Hello"); add("World"); add("Peace"); } }; //print element in l one by one l.forEach(TestConsumer.INSTANCE::sayHello);
看打印结果:
Hello Hello Hello World Hello Peace
证明我们的猜想是对的。
再试一下静态方法,修改上面的TestConsumer类,添加一个静态方法:
public static void greeting(String s){ System.out.println("Greeting "+s); }
还是替换 forEach() 中的参数:
l.forEach(TestConsumer::greeting);
这次和普通的静态方法一样,直接通过类访问函数对象。打印结果:
Greeting Hello Greeting World Greeting Peace
由上证明,Consumer接口对于静态和实例方法都是适用的。
另外,我们也可以实现一个方法,其他要求传入一个Consumer对象:
public class TestConsumer { public static void main(String[] args) { TestConsumer test = new TestConsumer(); test.tryConsumer(System.out::println, "hello"); } public void tryConsumer(Consumer c, String t){ c.accept(t); } }
仔细想来,这其实就有点类似于C/C++的传入方法指针之类的东西:Consumer可以根据传入的函数引用不用而执行不同的操作。
相关推荐
函数式编程(FP)是一种软件开发风格,它注重不依赖于编程状态的函数。函数式代码易于测试和复用,容易实现并发,且不容易受到bug的攻击。Scala是一种能很好支持函数式编程的新兴JVM语言。《Scala函数式编程》是针对...
Java 函数式编程教程 资源为视频教程资源 希望对你的 Java 学习有所帮助。
Java 8函数式编程学习笔记
Java8函数式编程超清学习
1. 学习函数式编程:通过阅读本源码资源,可以了解函数式编程的核心概念和在Java中的应用方式,为进一步学习函数式编程打下基础。 2. 实践函数式编程:本源码资源提供了丰富的函数式接口示例,帮助开发人员在实际...
java8 lambda 函数式接口 Stream流 并行流 Optional 方法引用
主要介绍了JAVA 函数式编程的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
那么,为什么函数式编程在Java中很危险呢?也许这个疑问普遍存在于很多程序员的脑中,作者Elliotte对此发表了一些见解,我们一起来看看他是怎么说的。 在我的日常工作中,我身边的开发者大多是毕业于CS编程院校...
一个简单的JavaScript函数式编程教程
引入Lambda表达式的作用是简化代码编写;函数接口的作用是让我们可以把函数包裹成函数接口,来实现把函数当做参数一样来使用(Java 不像 C 一样支持函数指针
函数式编程,这个词语由两个名词构成,函数,编程...函数,其实单独抽离出来这个词语,也并不陌生,那二者组合后的到底是什么呢,下面这篇文章主要给大家介绍了关于Java8函数式编程的相关资料,需要的朋友可以参考下。
## 目标我们将通过一系列练习一起发现函数式编程。 我们将看到基本模式和相关的约束。 ## 约束 任何变量都必须是final 。 因此,禁止进行循环,因为它需要一个可更改的计数器。 禁止类继承,只允许实现。 禁止...
Java函数式编程 课程大纲 ******* 课程大纲 ******* 了解函数式编程的基础知识-Lambda表达式,方法引用,流和函数接口。 for file in * ; do mv " ${file} " " ${file // - / } " ; done for file in * ; do mv " ...
公司常用到lamda表达式,有了这个资料,走遍天下都不怕
祖先-java8 通过浏览我的家谱来学习 Java 8 函数式编程。
1、函数式编程入门:通过阅读本源码资源,可以快速掌握Lambda表达式的基本语法和特性,为进一步学习函数式编程打下基础。 2、提高代码可读性:使用Lambda表达式可以减少样板代码,并使代码更加简洁和易读。本源码...
函数式编程的主要内容记住“该怎么办”? 将列表转换为流(与成员流中的每个成员做什么) 过滤器内部的含义(要过滤什么?) 使用方法参考的含义(执行什么?) (1)方法参考:-将列表转换为流(在列表中一一...
在Java中使用学习功能编程的自学练习。 #要求: 。 它不必是Oracle版本。 它可以是OpenJDK8 +或任何JDK 8或更高版本。 任何支持JUnit的东西都应该支持UncleJim。 文本编辑器或IDE #用法在这个专案上执行mvn clean ...
你厌烦函数式编程么?我也烦,我真想呼吁那些想我一样明智的人远离这种语言。 这里要澄清一点,我指的这种静态类型函数式编程语言,包括那种类型推断或者静态缺省等等。实际上,是Haskell和ML—family(包括...
Java8是Java发布以来改动最大的一个版本,其中主要添加了函数式编程、Stream、一些日期处理类。 函数式编程中中新加了一些概念:Lambda表达式、函数式接口、函数引用、默认方法、Optional类等;Stream中提供了一些...