简介

java 8引入了lambda表达式,lambda表达式实际上表示的就是一个匿名的function。

在java 8之前,如果需要使用到匿名function需要new一个类的实现,但是有了lambda表达式之后,一切都变的非常简介。

我们看一个之前讲线程池的时候的一个例子:

//ExecutorService using class
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable() {
@Override
public void run() {
log.info("new runnable");
}
});

executorService.submit需要接收一个Runnable类,上面的例子中我们new了一个Runnable类,并实现了它的run()方法。

上面的例子如果用lambda表达式来重写,则如下所示:

//ExecutorService using lambda
executorService.submit(()->log.info("new runnable"));

看起是不是很简单,使用lambda表达式就可以省略匿名类的构造,并且可读性更强。

那么是不是所有的匿名类都可以用lambda表达式来重构呢?也不是。

我们看下Runnable类有什么特点:

@FunctionalInterface
public interface Runnable

Runnable类上面有一个@FunctionalInterface注解。这个注解就是我们今天要讲到的Functional Interface。

Functional Interface

Functional Interface是指带有 @FunctionalInterface 注解的interface。它的特点是其中只有一个子类必须要实现的abstract方法。如果abstract方法前面带有default关键字,则不做计算。

其实这个也很好理解,因为Functional Interface改写成为lambda表达式之后,并没有指定实现的哪个方法,如果有多个方法需要实现的话,就会有问题。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

Functional Interface一般都在java.util.function包中。

根据要实现的方法参数和返回值的不同,Functional Interface可以分为很多种,下面我们分别来介绍。

Function:一个参数一个返回值

Function接口定义了一个方法,接收一个参数,返回一个参数。

@FunctionalInterface
public interface Function<T, R> { /**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);

一般我们在对集合类进行处理的时候,会用到Function。

Map<String, Integer> nameMap = new HashMap<>();
Integer value = nameMap.computeIfAbsent("name", s -> s.length());

上面的例子中我们调用了map的computeIfAbsent方法,传入一个Function。

上面的例子还可以改写成更短的:

Integer value1 = nameMap.computeIfAbsent("name", String::length);

Function没有指明参数和返回值的类型,如果需要传入特定的参数,则可以使用IntFunction, LongFunction, DoubleFunction:

@FunctionalInterface
public interface IntFunction<R> { /**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
R apply(int value);
}

如果需要返回特定的参数,则可以使用ToIntFunction, ToLongFunction, ToDoubleFunction:

@FunctionalInterface
public interface ToDoubleFunction<T> { /**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
double applyAsDouble(T value);
}

如果要同时指定参数和返回值,则可以使用DoubleToIntFunction, DoubleToLongFunction, IntToDoubleFunction, IntToLongFunction, LongToIntFunction, LongToDoubleFunction:

@FunctionalInterface
public interface LongToIntFunction { /**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
int applyAsInt(long value);
}

BiFunction:接收两个参数,一个返回值

如果需要接受两个参数,一个返回值的话,可以使用BiFunction:BiFunction, ToDoubleBiFunction, ToIntBiFunction, ToLongBiFunction等。

@FunctionalInterface
public interface BiFunction<T, U, R> { /**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);

我们看一个BiFunction的例子:

//BiFunction
Map<String, Integer> salaries = new HashMap<>();
salaries.put("alice", 100);
salaries.put("jack", 200);
salaries.put("mark", 300); salaries.replaceAll((name, oldValue) ->
name.equals("alice") ? oldValue : oldValue + 200);

Supplier:无参的Function

如果什么参数都不需要,则可以使用Supplier:

@FunctionalInterface
public interface Supplier<T> { /**
* Gets a result.
*
* @return a result
*/
T get();
}

Consumer:接收一个参数,不返回值

Consumer接收一个参数,但是不返回任何值,我们看下Consumer的定义:

@FunctionalInterface
public interface Consumer<T> { /**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);

看一个Consumer的具体应用:

//Consumer
nameMap.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));

Predicate:接收一个参数,返回boolean

Predicate接收一个参数,返回boolean值:

@FunctionalInterface
public interface Predicate<T> { /**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);

如果用在集合类的过滤上面那是极好的:

//Predicate
List<String> names = Arrays.asList("A", "B", "C", "D", "E");
List<String> namesWithA = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());

Operator:接收和返回同样的类型

Operator接收和返回同样的类型,有很多种Operator:UnaryOperator BinaryOperator ,DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator, DoubleBinaryOperator, IntBinaryOperator, LongBinaryOperator等。

@FunctionalInterface
public interface IntUnaryOperator { /**
* Applies this operator to the given operand.
*
* @param operand the operand
* @return the operator result
*/
int applyAsInt(int operand);

我们看一个BinaryOperator的例子:

 //Operator
List<Integer> values = Arrays.asList(1, 2, 3, 4, 5);
int sum = values.stream()
.reduce(0, (i1, i2) -> i1 + i2);

总结

Functional Interface是一个非常有用的新特性,希望大家能够掌握。

本文的例子:https://github.com/ddean2009/learn-java-streams/tree/master/functional-interface

更多内容请访问 www.flydean.com

java 8 Streams简介的更多相关文章

  1. [java] jsoup使用简介-汇率换算器实现-插曲2

    [java] jsoup使用简介-汇率换算器实现-插曲2 // */ // ]]>   [java] jsoup使用简介-汇率换算器实现-插曲2 Table of Contents 1 系列文章 ...

  2. Java Servlet 技术简介

    Java Servlet 技术简介 Java 开发人员兼培训师 Roy Miller 将我们现有的 servlet 介绍资料修改成了这篇易于学习的实用教程.Roy 将介绍并解释 servlet 是什么 ...

  3. Java基础类库简介

    Java基础类库简介 一.常用的基础类库:11个jar(Java Archive,Java归档)包 作为java语言使用者,我们可以感受到java语言带来的优势(平台无关.面向对象.多线程.高效易扩展 ...

  4. Java多线程概念简介 多线程中篇(一)

    Java的线程与操作系统的线程   在线程的相关介绍中,有讲到“线程的实现”分为三种:内核支持,用户级以及两者混合.(这只是一种简要的分类) Java线程在JDK1.2之前,是用户线程实现的 而在JD ...

  5. Understanding Java 8 Streams API---reference

    http://java.amitph.com/2014/01/understanding-java-8-streams-api.html Since past few versions, Java h ...

  6. Java 8 Streams的简单使用方法

    Java 8 Streams的简单使用方法 package JDK8Test; import java.util.ArrayList; public class Main { public stati ...

  7. Java编译器API简介

    今天给大家分享的是Java编译器API简介,文章部分内容摘自[优锐课]学习笔记. Java编译器API Java编译器API是Java模块(称为java.compiler)的一部分.该模块包括语言模型 ...

  8. java.math包简介

    java.math包提供了java中的数学类 包括基本的浮点库.复杂运算以及任意精度的数据运算   '可以看得到,主要包括三个类一个枚举 BigDecimal和BigInteger接下来会详细介绍 先 ...

  9. java.util.concurrent简介

    文章目录 主要的组件 Executor ExecutorService ScheduledExecutorService Future CountDownLatch CyclicBarrier Sem ...

随机推荐

  1. 前端之jQuery基础篇02-事件

    什么是事件: 在元素上移动鼠标. 选取单选按钮 点击元素 常见的DOM事件: 鼠标事件:click() 当鼠标单击发生click事件 : <!DOCTYPE html> <html& ...

  2. STL之vector常用函数笔记

    STL之vector常用函数笔记 学会一些常用的vector就足够去刷acm的题了 ps:for(auto x:b) cout<<x<<" ";是基于范围的 ...

  3. 最大子矩阵hdu1559(二维前缀和)

    最大子矩阵hdu1559 Problem Description 给你一个m×n的整数矩阵,在上面找一个x×y的子矩阵,使子矩阵中所有元素的和最大. Input 输入数据的第一行为一个正整数T,表示有 ...

  4. 使用Putty + Xming 远程登录Linux显示图形化界面

    一般我们远程登录linux 服务器,都是使用非加密的 telnet 或者加密的 ssh.这些登录方式有一个特点:只能登录字符界面,不能运行那些带有GUI界面的程序. 有时候为了学习或者工作的需要,我们 ...

  5. PTA数据结构与算法题目集(中文) 7-41PAT排名汇总 (25 分)

    PTA数据结构与算法题目集(中文)  7-41PAT排名汇总 (25 分) 7-41 PAT排名汇总 (25 分)   计算机程序设计能力考试(Programming Ability Test,简称P ...

  6. 面试官: 说说你对async的理解

    大家好,我是小雨小雨,致力于分享有趣的.实用的技术文章. 内容分为翻译和原创,如果有问题,欢迎随时评论或私信,希望和大家一起进步. 分享不易,希望能够得到大家的支持和关注. TL;DR async是g ...

  7. 搭建KVM

                                                                       系统&服务管理进阶 搭建KVM服务器 虚拟化概述 • vi ...

  8. python的字符串、列表、字典和函数

    一.字符串 在python中字符串无需通过像php中的explode或者javascript中的split进行分解即可完成切片,可以直接通过下标获取字符串中的每一个字符,下标从0开始,如果从厚望签署, ...

  9. Linux ssh登录出错

    今天登录远程主机的时候,出现了以下错误: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    WARNING: REMOT ...

  10. CDR

    伴随着新经济.独角兽一同被热议的,中国将很快推出存托凭证迎接独角兽回归.中国存托凭证(CDR)已成为当下热门话题.说不清CDR,还能和小伙伴们愉快地聊天吗? CDR到底是什么?它具有哪些优势?能否带来 ...