jdk8新特性学习总结

jdk8新增了一下几个新的特性

  • lambda表达式和函数式接口
  • 方法引用
  • stream流

这里stream流的api比较多在这篇文章就不详细展开了。

lambda表达式和函数式接口

lambda表达式

先简单介绍 一下lambda表达式:lambda表达式也可以称为是闭包,它允许把函数作为一个方法的参数传入到方法中,使用lambda表达式可以使代码更简介美观。

语法

我们来看下它的语法格式,很简单清晰

(入参)->{返回值}

他有如下几个特性

  • 可选类型声明:入参部分传参的时候可以不声明参数类型,编译器能直接统一识别参数类型。
  • 可选参数圆括号:入参部分是一个参数,那么可以把圆括号省略,如果是多个参数圆括号不能省略。
  • 可选大括号:如果打括号里只有一句代码就可以省略大括号。
  • 可选返回关键字:如果大括号内只有一个需要返回的值或则表达式,那么就可以省略return返回关键字。

使用

常见的几种写法

//无参不带括号且不带返回关键字
()->1;
//带返回关键字
()->return 1;
//带大括号
()->{return 1};
//有一个参数带小括号
(int a)->return a+1;
//不带小括号(不建议这么写)
a ->return a+1;
//多个参数,不写参数类型
(a,b)->{a+b};
//有参打印一句话
(String a)->System.out.printl(a)

大致的写法就是这样,后面会有更详细的用法。
lambda表达式常常和函数式接口一起使用,那么我们就来了解一下函数式接口

函数式接口

函数式接口首先它是个接口,然后这个接口里面有且仅有一个抽象方法,然后在该接口上加一个@FunctionalInterface注解,那么它就是一个函数式接口了。

语法

@FunctionalInterface
public interface FunctionIntfaceDemo {
    String test1();
}

这样就简单定义了一个函数式接口。

如何使用

其实函数式接口可以隐式转换为lambda表达式
像上面我们定义的那个函数式接口它就可以用lambda表达式这么写

()->"返回一个String类型的参数";

或者直接赋值

FunctionIntfaceDemo test = ()->"返回一个String类型的参数";

java 给我们提前定义好了4个常用的函数式接口
分别是Functio< R, T>,Consumer,Supplier,Predicate。
接下来慢慢解释着几个函数的作用。
这里我们只简单的了解不做深入的讨论

Function< R,T >

这个函数它接收一个R对象类型的值,然后返回一个T对象类型的值,然后通过调用apply方法去执行内容。
我们直接看用法,这里我为了方便大家观察就不去简写lamdba表达式了

Function<Integer,Integer> s =(Integer a)->{return a+2;};
Integer apply = s.apply(2);

这里接收的参数必须是对象类型,不能是基础类型。
这串代码接收了一个integer类型的a,然后返回了一个integer类型的a+2。接着调用了apply传入了一个2,获得了一个结果。

关于Function的细节部分就不展开了,不然这篇文章就长了

Consumer

Consumer是消費者的意思,Consumer< V>就是接收一个V对象的值,然后不返回,本质上就接收的这个对象被消费掉了。然后使用accept去执行。

Consumer<Integer> consumer = (a)-> System.out.println(a) ;
consumer.accept(5);

Supplier

Supplier是提供者的意思,和上面的消費者相反,它不接收参数,Supplier< T>返回一个T对象类型的值。通过调用get方法执行。

Supplier<String> supplier = () -> "提供产品";
String s1 = supplier.get();

Predicate

这个单词翻译过来是谓语的意思,它是一个谓语接口Predicate< T,Boolean>它接收一个T类型的对象然后返回一个布尔值,通过test方法执行。其实它和Function一样,但是为了区分开来所以单独划分了出来。

Predicate<Integer> predicate = (Integer a) -> a >= 10;
boolean test1 = predicate.test(15);

其它接口

其实Java给我们提供了40多种函数接口,前面介绍的是最基础的四种接口。剩下的几个接口都是上面几个接口的变式,大多数都是对参数类型和参数数量做了限制。这里我们分别举一个例子

参数类型限制的接口:IntToDoubleFunction,接受一个int类型输入,返回一个double类型结果。这里同时限制了入参和返回值。这个就是Function的变种。

返回值类型限制的接口:DoubleSupplier,代表一个double值结构的提供方,其实它就是Supplier的变种

数量限制接口:这类接口需要接收两个参数,此类接口的名字前面一般都是Bi开头Binary(二元的意思),比如BiConsumer< T,U>,代表了一个接受两个输入参数的操作,并且不返回任何结果。

Operator接口:这类接口就是一种简写一般用于两个相同类型的计算,这类型的接口总共就两种(不是两个),分别是一元操作的UnaryOperator< T>,接受一个参数为类型T,返回值类型也为T。和BinaryOperator,代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果。

方法引用

方法引用我们可以理解为lambda表达式的另外一种形式具体概念就不多说了。

方法引用主要有四类,分别是静态方法引用实例方法引用对象方法引用以及构造方法引用

接下来我们一个一个看他们的使用方法

我们先看下他们对应的语法格式

//静态方法引用
类名::静态方法
//实例方法引用
对象实例名::实例方法
//对象方法引用
对象名::实例方法
//构造方法引用
类名::new

上面这样提现出来可能不是太清晰,我们来具体看一下代码

代码举例

这里是列举了上面的语法结构,其实在使用时候可以很灵活。

public class MethodReferenceDemo {

    static void StaticMethodQuote(){
        System.out.println("静态方法引用");
    }

    void InstanceMethodQuote(){
        System.out.println("实例方法引用");
    }

    MethodReferenceDemo(){
        System.out.println("构造方法的引用");
    }
    public static void main(String[] args) {
        //静态方法引用
        Runnable staticMethodQuote = MethodReferenceDemo::StaticMethodQuote;
        staticMethodQuote.run();
        //实例方法引用
        MethodReferenceDemo methodReferenceDemo = new MethodReferenceDemo();
        Runnable instanceMethodQuote = methodReferenceDemo::InstanceMethodQuote;
        instanceMethodQuote.run();
        //对象方法引用
        Consumer<MethodReferenceDemo> objectMethodQuote = MethodReferenceDemo::InstanceMethodQuote;
        objectMethodQuote.accept(new MethodReferenceDemo());
        //构造方法的引用
        Runnable aNew = MethodReferenceDemo::new;
        aNew.run();
    }
}

我们来看下打印结果

静态方法引用
构造方法的引用
实例方法引用
构造方法的引用
对象方法的引用
构造方法的引用

这里构造方法的引用打印了三次是因为,我们将对象实例化了三次,除了静态方法的引用其余的都调用了构造方法。

其实上面的方法引用是可以直接转成lambda表达式的
大致就是这个样子

//静态方法引用
Runnable staticMethodQuoteLambda = () -> MethodReferenceDemo.StaticMethodQuote();
//实例方法引用
Runnable instanceMethodQuoteLambda = () -> methodReferenceDemo.InstanceMethodQuote();
//对象方法引用
Consumer<MethodReferenceDemo> objectMethodQuoteLambda= (objectMethodQuoteParameter)->objectMethodQuoteParameter.ObjectMethodQuote();
objectMethodQuoteLambda.accept(new MethodReferenceDemo());
//构造方法引用
Runnable ConstructionMethodLam = () -> new MethodReferenceDemo();

总结一下大概是这样的

//静态方法引用
(参数)->类名.静态方法(参数)
//实例方法引用
(参数)->实例名.实例方法(参数)
//对象方法引用
(对象,参数)->类名.实例方法(参数)
//构造方法引用
(参数)->new 类名(参数)

所以本质上这些东西区别也特别大

关于stream后面有时间就在专门写一篇总结下。

posted @ 2020-05-07 17:39  ccsert  阅读(205)  评论(0编辑  收藏  举报