vlambda博客
学习文章列表

函数式接口及Lamada表达式

随着jdk1.8使用的越来广函数式接口和Lamada表达式作为其中的2重要新特性学习并掌握它已经成为必如果看过一些开源项目的源码就会发现函数式接口和Lamada表达式几乎都有使用。


一、jdk1.8接口的3个新特性

1、default关键字,这里的default用于修饰方法的(jdk1.8新特性而且只能在interface接口里修饰方法,被修饰的方法必须包含方法体


2、static关键字,jdk1.8允许在接口里修饰方法,被static修饰的方法必须包含报文体


3、注解@FunctionalInterface

用于表示当前接口类为函数式接口,而且这个函数式接口必须有且只能有一个实现的方法而defaultstatic修饰的方法不算待实现的方法


代码展示如下:

public interface User {

   
public String getName();

   
public int getAge();
}

传统的接口,全部都是未实现的方

public interface User {

    
public default String getName(){
        
return "zhang";
    };

    
public default int getAge(){
        
return 1;
    };
}

全部都是已实现的方法,但是不是函数式接口,因为函数式接口要有一个实现的方法

public interface User {

   
public String getName();

   
public default int getAge(){
       
return 1;
    };

   
static void print() {
       
System.out.println("hello");
    }
}

虽然没有用@ FunctionalInterface注解修饰类,但是也是符合函数接口的条件:有且只有一个未实现的方法

@FunctionalInterface

public interface User {

    
public String getName();

    
public default int getAge(){
        
return 1;
    };

    
static void print() {
        
System.out.println("hello");
    }
}

标准的函数式接口


二、jdk1.8新增的函数式接口

Jdk1.8新增一个函数式接口的:java.util.function,里面包含了下面这么多接口:


BiConsumer

BiPredicate

BooleanSupplier

Consumer

DoubleConsumer

DoubleFunction

DoublePredicate

DoubleSupplier

DoubleToIntFunction

DoubleToLongFunction

DoubleUnaryOperator

IntConsumer

IntPredicate

IntSupplier

LongConsumer

LongFunction

LongPredicate

LongSupplier

LongToDoubleFunction

LongToIntFunction

LongUnaryOperator

ObjDoubleConsumer

ObjIntConsumer

ObjLongConsumer

Predicate

Supplier

ToDoubleBiFunction

ToDoubleFunction

ToIntBiFunction

ToIntFunction

ToLongBiFunction

ToLongFunction

UnaryOperator

IntUnaryOperator

IntToDoubleFunction

IntFunction

IntToLongFunction

LongBinaryOperator

IntBinaryOperator

DoubleBinaryOperator

BiFunction

BinaryOperator

Function


归纳总结一下就是下面几类:

Java.util.function下的函数式接口类型

说明

Consumer

有参数,无返回值

Function

有参数,有返回值

Predicate

有参数,返回boolean

Supplier

参数,有返回值


Consumer类源码

public interface Consumer<< span="">T> {

   
/**
     * Performs this operation on the given argument.
     *
     *
@param t the input argument
     */
   
void accept(T t);

   
/**
     * Returns a composed {
@code Consumer} that performs, in sequence, this
     * operation followed by the {
@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {
@code after} operation will not be performed.
     *
     *
@param after the operation to perform after this operation
     *
@return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {
@code after} operation
     *
@throws NullPointerException if {@code after} is null
     */
   
default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.
requireNonNull(after);
        return
(T t) -> { accept(t); after.accept(t); };
   
}
}


Function

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);

   
/**
     * Returns a composed function that first applies the {
@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     *
@param <V> the type of input to the {@code before} function, and to the
     *           composed function
     *
@param before the function to apply before this function is applied
     *
@return a composed function that first applies the {@code before}
     * function and then applies this function
     *
@throws NullPointerException if before is null
     *
     *
@see #andThen(Function)
     */
   
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.
requireNonNull(before);
        return
(V v) -> apply(before.apply(v));
   
}

   
/**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {
@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     *
@param <V> the type of output of the {@code after} function, and of the
     *           composed function
     *
@param after the function to apply after this function is applied
     *
@return a composed function that first applies this function and then
     * applies the {
@code after} function
     *
@throws NullPointerException if after is null
     *
     *
@see #compose(Function)
     */
   
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.
requireNonNull(after);
        return
(T t) -> after.apply(apply(t));
   
}

   
/**
     * Returns a function that always returns its input argument.
     *
     *
@param << span="">T> the type of the input and output objects to the function
     *
@return a function that always returns its input argument
     */
   
static <T> Function<T, T> identity() {
       
return t -> t;
   
}
}


Predicate

@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);

   
/**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {
@code false}, then the {@code other}
     * predicate is not evaluated.
     *Any exceptions thrown during evaluation of either predicate are relayed     *

    * to the caller; if evaluation of this predicate throws an exception, the

* {@code other} predicate will not be evaluated.

*
     * 
@param other a predicate that will be logically-ANDed with this
     *              predicate
     * 
@return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {
@code other} predicate

@throws NullPointerException if other is null
     */
    
default Predicate<Tand(Predicate<? super T> other) {
        Objects.
requireNonNull(other);
        return 
(t) -> test(t) && other.test(t);
    
}


/**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * 
@return a predicate that represents the logical negation of this
     * predicate
     */

default Predicate<Tnegate() {
        
return (t) -> !test(t);
    
}


default Predicate<Tor(Predicate<? super T> other) {
        Objects.
requireNonNull(other);
        return 
(t) -> test(t) || other.test(t);
    
}


static <T> Predicate<TisEqual(Object targetRef) {
        
return (null == targetRef)
                ? Objects::
isNull
                
: object -> targetRef.equals(object);
    
}
}

     

Supplier

@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);


default Predicate<Tand(Predicate<? super T> other) {
        Objects.
requireNonNull(other);
        return 
(t) -> test(t) && other.test(t);
    
}


default Predicate<Tnegate() {
        
return (t) -> !test(t);
    
}


default Predicate<Tor(Predicate<? super T> other) {
        Objects.
requireNonNull(other);
        return 
(t) -> test(t) || other.test(t);
    
}


static <T> Predicate<TisEqual(Object targetRef) {
        
return (null == targetRef)
                ? Objects::
isNull
                
: object -> targetRef.equals(object);
    
}
}


三、Jdk1.8以前旧接口中的函数式接口

Runnable

@FunctionalInterface
public interface Runnable {
   
/**
     * When an object implementing interface
Runnable is used
     * to create a thread, starting the thread causes the object's
     *
run method to be called in that separately executing
     * thread.
     *

     public abstract void run();
}


Java.io.FileFilter

@FunctionalInterface
public interface FileFilter {

   
/**
     * Tests whether or not the specified abstract pathname should be
     * included in a pathname list.
     *
     *
@param  pathname  The abstract pathname to be tested
     *
@return  true if and only if pathname
    
*          should be included
     */
   
boolean accept(File pathname);
}

Java.io.FilenameFilter

@FunctionalInterface
public interface FilenameFilter {
   
/**
     * Tests if a specified file should be included in a file list.
     *
     *
@param   dir    the directory in which the file was found.
     *
@param   name   the name of the file.
     *
@return  true if and only if the name should be
     * included in the file list;
false otherwise.
     */
   
boolean accept(File dir, String name);
}


四、Lamada表达式

语法

(参数1,参数2,) -> {代码块}


意义:

实现函数式接口未实现的方法


4.1无参用法

@FunctionalInterface
public interface User {

   
public String getName();

    public default int
getAge(){
       
return 1;
   
};

    static void
print(){} ;
}

public class LamadaTest {
    @Test
    public void testLamada(){
        User user = ()->{return "zhang";};
        System.out.println(user.getName());
    }
}

到这里可以能有人会有疑惑,()->{return "zhang";}”这段代码怎么就知道实现User类的getName方法,其实是倒着推导的,因为用的是User类取接收的,而且User类符合函数式接口条件只有一个未实现的方法,所以这里就知道是实现User接口的getName方法。


如果通过方法的参数一个泛型接口类,也是通过方法参数的类型来倒实现的是哪个类的什么方法代码如下:

public class LamadaTest {
   
@Test
   
public void testLamada(){
        printUser(()->{
return "zhang";});
   
}

   
void printUser(User user){
        System.
out.println(user.getName());
   
}
}


参用法

@FunctionalInterface
public interface User {

   
public void printName(String name);

}

public class LamadaTest {
   
@Test
   
public void testLamada(){
        printUser((String t)->{System.
out.println(t);});
   
}

   
void printUser(User user){
        user.printName(
"zhang");
   
}
}

可以看出Lamada表达式实现接口方法时和User接口定义printName方法时的形参不一致,这里形参不一致可以的。


如果实现方法里只有一行语句,如代码中的System.out.println(t)那这个大括号是可以去掉,如下所示:

public void testLamada(){
    printUser((String t)->System.out.println(t));
}


如果方法体只有一句,且方法的参数跟方法里面语句的参数一致,还可以用方法引用方式来写,方法引用通过“::”实现。IDEA工具会提示Lamada的简写方式(可以简写的语句标黄把光标放在这段代码中按“alt+enter”会自动转换成简写方式。

public void testLamada(){
    printUser(System.
out::println);
}



精选推荐:











*本文为IT技术栈原创文章,独家版权归于本平台,受到原创保护。任何渠道的转载请后台留言联系授权,侵权必究。