JAVA  lambda 表达式

目录

JAVA  lambda 表达式 1

概要 1

一. 函数式接口的概念 1

二. 例子 2

2.1自定义一个只有一个方法的接口如下 2

2.2接口的实现调用 2

三. ForEach 3

四:Lambda方法的传递 5

 

JAVA  lambda 表达式

概要

Java8已经出来好几年了,现在依然有很多人在用java7,在技术方面固步自封自然不是好事,接受新的事物,与时俱进才不会被淘汰。面向对象编程,这么多年一直很火热,但是受制于语法的复杂,在近年来出现了一些优秀的函数是编程,在函数是编程的概念里,方法也是甚至可以当作参数传递。Java8的lambda表达式其实就是想函数编程靠近的一种新的编程方式,它的语法简单,减少了代码的冗余,相较与以往的内部类写起来更简单,下面我们来一起看看lambda的使用方式。

学习Lambda表达式必须得了解的概念:函数式接口。

在函数式编程语言中,Lambda表达式的类型是函数。

而在Java中,Lambda表达式是对象,它们必须依附于一类特别的对象类型——函数式接口(Functional Interface)。

接下来我们看下函数式接口的定义:

  1. 如果一个接口中,有且只有一个抽象的方法(Object类中的方法不包括在内),
  2. 那这个接口就可以被看做是函数式接口,它被@FunctionalInterface修饰。

 

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

上面是Runnable接口的声明,在Java8后,Runnable接口多了一个FunctionalInterface注解,表示该接口是一个函数式接口。但是如果我们不添加FunctionalInterface注解的话,如果接口中有且只有一个抽象方法时,编译器也会把该接口当做函数式接口看待。

 

 

 

2.1自定义一个只有一个方法的接口如下

public interface MyLambda<T> {
    public T getData(T t);
}

2.2接口的实现调用

  1. 以前的实现方式,是直接用匿名内部类的方式


public class Main {
    public static void main(String[] args) {
        MyLambda<String> myLambda=new MyLambda<String>() {
            @Override
            public String getData(String s) {
                return s+" test";
            }
        };
        System.out.println(myLambda.getData( "hello" ));
    }
}

  1. 替换成 Lambda

public class Main {
    public static void main(String[] args) {
        MyLambda<String> myLambda= s -> s+" test";
        System.out.println(myLambda.getData( "hello" ));
    }
}

由此可见,你可以简单将lambda表达式看成匿名内部类的简写形式。我们来分析一下,仔细看上面两部分的代码,对比一下,第一部分的getData(String S),和第二部分的 s ->其实s ->

就是对getData(String S)的实现,既然如此那么我们当然可以把Lambda部分直接写成 (String  s)-> s+" test";或者是(s) -> s+" test";这个时候相比你以及该看出来了,->左侧是方法的参数,右侧是方法的实现。之所以左侧可以省略类型,是因为接口中只有一个方法,java内部推断机制,可以直接推断出类型,因此在实现的时候根本不需要指定类型。一般lambda有以下几种类型。

  1. ()-> 66接口中的方法不需要参数,并且该方法的返回值为 66
  2. (x)->x+test 该方法接受一个参数x,最后返回了一个x+test的返回值
  3. ()-> {

    总结:->右侧是对方法的实现,因此这部分是方法体的代码,当方法体只有一句话的时候大括号可以省略,当多行的时候你需要加上大括号。

}

熟悉scala的同学,肯定对forEach不陌生。它可以迭代集合中所有的对象,java8中也提供了forEach()迭代功能。下面是java的集合类遍历集合的操作,在这里我们来探讨一下ForEach()。

List<String> list = new ArrayList<>(  );
list.add( "北京" );
list.add( "欢迎" );
list.add( "你" );
list.forEach( s -> System.out.println(s) );

看到这里相比你就明白了,forEach里面其实就是Lambda表达式,我们打开源码看。

public interface Iterable<T> {
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();

    /**
     * Performs the given action for each element of the {@code Iterable}
     * until all elements have been processed or the action throws an
     * exception.  Unless otherwise specified by the implementing class,
     * actions are performed in the order of iteration (if an iteration order
     * is specified).  Exceptions thrown by the action are relayed to the
     * caller.
     *
     * @implSpec
     * <p>The default implementation behaves as if:
     * <pre>{@code
     *     for (T t : this)
     *         action.accept(t);
     * }</pre>
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */


    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

 

 

}

看见没,forEach方法里面的参数是一个Consumer<T> action接口,接着在for循环里遍历了Iterator<T>然后将遍历出的每一个元素传递到了action里面的accept()方法中,下面打开Consumer<T>

 

//Consumer明显就是一个函数是接口

@FunctionalInterface
public interface Consumer<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); };
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

四:Lambda方法的传递

前面说过,函数是编程语言,方法可以当作参数传递,javaLambda虽然没能完全的实现这样的逻辑,但是也有了基本的应用,下面介绍一下Lambda  “::”进行方法的传递。

  1. 首先我们自定义一个符合Lambda的函数式接口

@FunctionalInterface
public interface MyLambda<T> {
    public T accept(T t);
}

该接口有一个自定义的方法,这个方法返回一个T类型的数据。这个接口中的方法必须要被实现才可以用,这个大家都知道的。其实并不需要你每一次都再用的时候去实现,你可以去别的方法里面直接拿一个和accept方法特性一样(特性一样的意思是,你不能将没有返回值的方法传递给有返回值的接口,饭之亦然)的方法直接将其当作accept来用,这就相当于将别的类的方法传递给了MyLambda<T>这个接口。话不多说,下面我们自定义一个Test类。

  1. class Test {
        // static methods
        static String startsWith(String s) {
            return s;
        }
       public String  endWith(String s) {
            return s;
        }
    }

 

 

  1. 实现普通方法传递:

public class Main {
    public static void main(String[] args) {
        Test test = new Test();

//将test类中的方法当成accept方法的实现体,myLambda.accept()实际上调用的就是test中的//endwith方法
        MyLambda<String> myLambda = test::endWith;
        System.out.println( myLambda.accept( "lambda lambda lambda lambda" ) );
    }
}

  1. 实现静态方法的传递

 

public class Main {
    public static void main(String[] args) {
        MyLambda<String> myLambda = Test::startsWith;
        System.out.println( myLambda.accept( "lambda lambda lambda lambda" ) );
    }
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我先森

鼓励一个吧,哈哈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值