【Java中级】4.0 Java中lambda表达式(下)

【Java】3.0 Java中lambda表达式(上)
【Java】4.0 Java中lambda表达式(下)

7.0 lambda表达式与异常

lambda表达式也可以抛出异常,但是异常必须与函数式接口的抽象方法中的throws子句中列出的异常兼容。如下例所示。

package com.edpeng.game1;

interface DoubleNumericArrayFunc {
    // 接口也必须定义抛出自定义异常EmptyArrayException
    double func(double[] n) throws EmptyArrayException;
}

@SuppressWarnings("serial")
class EmptyArrayException extends Exception {
    EmptyArrayException() {
        super("Array Empty");
    }
}

public class test1 {

    public static void main(String[] args) 
            throws EmptyArrayException {
        double[] values = { 1.0, 2.0, 3.0, 4.0 };
        //计算一个double数组的值,但当数组为0时
        //抛出自定义异常EmptyArrayException
        DoubleNumericArrayFunc average = (n) -> {
            double sum = 0;
            
            if (n.length == 0)
                throw new EmptyArrayException();

            for (int i = 0; i < n.length; i++) {
                sum += n[i];
            }
            return sum / n.length;
        };

        System.out.println("数组的平均数为: \n" 
        + average.func(values));

        // 这将导致引发异常
        System.out.println("数组的平均数为: \n" 
        + average.func(new double[0]));
    }
}

执行结果如下:


图片.png

这里需要注意的是,lambda表达式中的参数依旧是“(n)”,代表的是一个double[ ]数组,而不是“n[ ]”,lambda表达式能从目标上下文推出是double[ ],所以“(n)”的类型也是double[ ],没必要写成“n[ ]”(这么做也不合法)。
但是可以显示的写成(声明)为“double[] n”,这么做是合法的,但是在本例中这么做不会有什么好处。

8.0 lambda表达式与变量捕获

先看一个简单的例子。

package com.edpeng.game1;

interface MyFunc {
    int func(int n);
}

public class test1 {

    public static void main(String[] args) {
        int num = 10;
        MyFunc mylambda = (n) -> {
            int v = num + n;
            num++;
            return v;
        };
    }
}

编译都无法通过,代码“num++;”提示报错。

图片.png

我们可以看到,提示“在封闭范围内定义的局部变量num必须是fiinal或有效的fiinal。

  • 可见,lambda表达式可以访问其外层作用域内定义的变量。比如上例可以直接调用num。lambda表达式也可以显式或隐式地访问this变量。
  • 当,lambda表达式访问其外层作用域内定义的变量时,会产生一种特殊情况,这种情况就叫“变量捕获”。此时,lambda表达式智能使用实质上的final局部变量。实质上final的变量是指第一次赋值之后,值便不再发生变化的变量。没必要将这种变量声明为final,不过可以这么做,也不会错。(外层作用域的this参数自动是实质上的final的变量,lambda表达式没有自己的this参数)。所以如下这样也是无法编译运行的:
public static void main(String[] args) {
        int num = 10;
        num = 52;
        MyFunc mylambda = (n) -> {
            int v = num + n;
//          num++;
            return v;
        };
    }
  • lambda表达式不能修改外层作用域内的局部变量, 修改局部变量会移除其实质上的final状态,从而使得捕获该变量变得不合法。lambda表达式内部定义的变量可以随意修改。
9.0 方法引用

有一个重要的特性与lambda表达式相关,叫方法引用。方法引用提供一种引用而不执行方法的方式。往往两者伴随使用。

9.1 静态方法引用

创建静态方法引用,需要用到以下一般语法:

ClassName::methodName

类名和方法名之间使用双冒号隔开。“::”是JDK8新增的一个分隔符,专门用于此目的。 如果函数式接口的实现恰好是通过调用一个静态方法来实现,那么就可以使用静态方法引用。
具体演示代码如下:

package com.edpeng.game1;

interface StringFunc {
    String func(String n);
}

public class test1 {

    static String strReverse(String str) {
        String result = "";
        int i;

        for (i = str.length() - 1; i >= 0; i--) {
            result += str.charAt(i);
        }
        return result;
    }
}

class MethodRefDemo {
    static String stringOp(StringFunc sf, String s) {
        return sf.func(s);
    }

    public static void main(String[] args) {
        String inStr = "lambda表达式加入Java";
        String outStr;

        outStr = stringOp(test1::strReverse, inStr);

        System.out.println("原始字符串为: \n" + inStr);
        System.out.println("倒转后的字符串为: \n" + outStr);
    }
}

执行结果为:


图片.png

可能有人不太明白静态方法引用这个概念。如下这张表可以简单了解一下:

类型 语法 对应的lambda表达式
静态方法引用 类名::staticMethod (args) -> 类名.staticMethod(args)
实例方法引用 inst::instMethod (args) -> inst.instMethod(args)
对象方法引用 类名::instMethod (inst,args) ->类名.instMethod(args)
构造方法引用 类名::new (args) -> new 类名(args)

这里只说静态方法,代码演示如下:

public class StaticExample {
 
    /**
     * 无参数有返回值
     * @return
     */
    public static String put() {
        System.out.println("put method");
        return "hello";
    }
 
    /**
     * 有参数无返回值
     * @param size
     */
    public static void con(String size) {
        System.out.println("size: " + size);
    }
 
    /**
     * 带有一个参数一个返回值
     * @param str
     * @return
     */
    public static String toUpperCase(String str) {
        return str.toUpperCase();
    }
 
    /**
     * 带有两个参数一个返回值
     * @param s1
     * @param s2
     * @return
     */
    public static Integer len(String s1, String s2) {
        return s1.length() + s2.length();
    }
 
    public static void main(String[] args) {
        /**
         * 无参数有返回值
         */
 
        //lambda表达式的写法
        Supplier<String> stringSupplier= ()-> StaticExample.put();
        System.out.println(stringSupplier.get());
 
        //方法引用
        Supplier<String> stringSupplier2 = StaticExample::put;
        System.out.println(stringSupplier.get());
 
        /**
         *  有参数无返回值
         */
        //lambda表达式的写法
        Consumer<String> consumer = (x)-> StaticExample.con(x);
        consumer.accept("100");
        //方法引用
        Consumer<String> consumer2= StaticExample::con;
        consumer.accept("100");
 
        /**
         * 有1个参数有一个返回值
         */
        //lambda表达式的写法
        Function<String,String> function = (x)-> StaticExample.toUpperCase(x);
        System.out.println(function.apply("dada"));
 
        //方法引用的写法
        Function<String,String> function1= StaticExample::toUpperCase;
        System.out.println(function1.apply("dada"));
 
        /**
         * 有两个参数一个返回值
         */
        //lambda表达式的写法
        BiFunction<String,String,Integer> biFunction= (s1,s2)-> StaticExample.len(s1,s2);
        Integer apply = biFunction.apply("dada", "dada");
        System.out.println(apply);
 
        //方法引用的写法
        BiFunction<String,String,Integer> biFunction2= StaticExample::len;
        Integer apply2 = biFunction2.apply("dada", "dada");
        System.out.println(apply2);
    }
}

这个演示案例抄别个的,虽然啰嗦,但是很完整,思路简单,很好理解。

9.2 实例方法的方法引用

实例方法于9.1中有格式写法的简单介绍。格式为:

objRef::mwthodName

可以看到,很静态方法语法特别类似,不过这里使用对象引用而不是类名。演示代码如下:

package com.edpeng.game1;

interface StringFunc {
   String func(String n);
}

class MyStringOps{
   String strReverse(String str) {
       String resultStr = "";
       int i;
       
       for(i= str.length()-1;i>=0;i--) {
           resultStr +=str.charAt(i);
       }
       return resultStr;
   }
}

public class test1 {

   static String stringOp(StringFunc sf,String s) {
       return sf.func(s);
   }
   
   public static void main(String[] args) {
       String inStr ="lambda表达式加入Java";
       String outStr;
       
       MyStringOps stringOps = new MyStringOps();
       outStr= stringOp(stringOps::strReverse, inStr);
       
       System.out.println("原始字符串为:  \n"+inStr);
       System.out.println("倒转后的字符串为: \n"+outStr);
   }
}

执行结果为:


图片.png

上述例子应该不算难理解,下面通过另一个案例代码演示,进一步深入:

package com.edpeng.game1;

interface MyFunc<T> {
    boolean func(T v1, T v2);
}

class HighTemp {
    private int hTemp;

    HighTemp(int ht) {
        hTemp = ht;
    }
    
    //判断是否两个温度相等
    boolean sameTemp(HighTemp ht2) {
        return hTemp == ht2.hTemp;
    }
    //判断是否参数温度是否比指标温度要高
    boolean lessThanTemp(HighTemp ht2) {
        return hTemp < ht2.hTemp;
    }
}

public class test1 {
    static <T> int counter(T[] vals, MyFunc<T> f, T v) {
        //第一个参数是查询温度列表
        //第二个参数是查询内容
        //第三个参数是查询指标
        int count = 0;

        for (int i = 0; i < vals.length; i++) {
            if (f.func(vals[i], v)) {
                count++;
            }
        }
        return count;
    }
    public static void main(String[] args) {
        int count;
        
        HighTemp[] weekDayHighs = {
                new HighTemp(89),new HighTemp(82),
                new HighTemp(90),new HighTemp(89),
                new HighTemp(91),new HighTemp(84),
                new HighTemp(83)
        };
        
        HighTemp[] weekDayHighs2 = {
                new HighTemp(32),new HighTemp(12),
                new HighTemp(24),new HighTemp(19),
                new HighTemp(18),new HighTemp(12),
                new HighTemp(-1),new HighTemp(13)
        };
        
        count= counter(weekDayHighs, HighTemp::sameTemp, new HighTemp(89));
        System.out.println(count+"天的温度超过89摄氏度");
        count= counter(weekDayHighs2, HighTemp::sameTemp, new HighTemp(12));
        System.out.println(count+"天的温度超过12摄氏度");
        
        count = counter(weekDayHighs, HighTemp::lessThanTemp, new HighTemp(89));
        System.out.println(count+"天的温度最高不超过89摄氏度");
        count = counter(weekDayHighs2, HighTemp::lessThanTemp, new HighTemp(19));
        System.out.println(count+"天的温度最高不超过19摄氏度");
    }
}

运行结果如下:


图片.png

这里存在多重引用,有HighTemp两个实例方法:sameTemp()和lessThanTemp(),作用代码里面说明了,这两个方法都需要一个HighTemp类型的参数,并且都返回布尔结果。因此这两个方法都与MyFunc函数式接口兼容,调用的时候,对象类型可以映射到func()的第一个参数,传递的实参可以映射到func()第二个参数。
我们看实例方法引用的表达式:

HighTemp::sameTemp

被传递给counter方法时,会创建函数式接口MyFunc的一个实例,第一个参数的参数类型就是实例方法的调用对象的类型,也就是HighTemp。第二个参数的类型也是HighTemp,是sameTemp()或者lessThanTemp()方法的参数。

另外,可以通过super引用方法的超类版本,如下所示:

super::name

方法的名称由name指定。

9.3 泛型中的方法引用

意思就是泛型类或者泛型方法中也可以用方法引用。看代码:

package com.edpeng.game1;

interface MyFunc<T> {
    int func(T[] vals, T v);
}

class MyArrayOps {
    static <T> int countMatching(T[] vals, T v) {
        int count = 0;

        for (int i = 0; i < vals.length; i++) {
            if (vals[i] == v) {
                count++;
            }
        }
        return count;
    }
}

public class test1 {
    static <T> int myOp(MyFunc<T> f,T[] vals,T v) {
        return f.func(vals, v);
    }
    
    public static void main(String[] args) {
        Integer[] vals = {1,2,3,4,2,3,4,4,5};
        String[] strs = {"One","Two","Three","Two"};
        int count;
        
        count = myOp(MyArrayOps::<Integer>countMatching, vals,4);
        System.out.println("vals数列中包含"+count+"个4");
        
        count = myOp(MyArrayOps::<String>countMatching, strs,"Two");
        System.out.println("strs数列中包含"+count+"个Two");
    }
}

执行结果如下:


图片.png
  • 这里首先注意的是一种语法用法:
 count = myOp(MyArrayOps::<Integer>countMatching, vals,4);

这里传递的参数类型为Integer,这个东西发生在“::”之后,这种语法特别建议经常用。但是,对于指定泛型类的情况下,类型参数位于类名的后面,“::”的前面。

  • 代码中,MyArrayOps是非泛型类,但是有泛型方法countMatching()。该方法返回数组中与指定值匹配的元素的个数,这里用泛型意味着可以匹配任何数据类型的数组。
class MyArrayOps {
    static <T> int countMatching(T[] vals, T v) {
        int count = 0;

        for (int i = 0; i < vals.length; i++) {
            if (vals[i] == v) {
                count++;
            }
        }
        return count;
    }
}

之前9.3的案例代码都没有体现使用方法引用机制的真正优势,方法引用和集合框架一起使用时,才是一展拳脚的地方。(之后会开一篇专门介绍集合框架的文章。)

9.5 举一个简单有效的例子。代码作用是使用方法引用来帮助确定集合中最大的元素。

先看完整代码:

package com.edpeng.game1;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

class MyClass {
    private int val;

    public MyClass(int v) {
        val = v;
    }

    int getVal() {
        return val;
    }
}

public class test1 {
    static int compareMC(MyClass a, MyClass b) {
        return a.getVal() - b.getVal();
    }

    public static void main(String[] args) {
        ArrayList<MyClass> aList = new ArrayList<MyClass>();

        aList.add(new MyClass(1));
        aList.add(new MyClass(4));
        aList.add(new MyClass(2));
        aList.add(new MyClass(9));
        aList.add(new MyClass(3));
        aList.add(new MyClass(7));

        MyClass maxValObj = Collections.max(aList, test1::compareMC);

        System.out.println("最大值为:\n" + maxValObj.getVal());
    }
}

执行结果为:


图片.png

Java集合框架都在Java.util包里面,提供很多复杂的接口和类层次,功能很多,我们用到的是java.util.Collections包中的max()方法。

MyClass maxValObj = Collections.max(aList, test1::compareMC);

这个方法主要接受两个参数,类型均为比较的对象的类型,如果第一个参数大于第二个参数,该方法返回一个正数,如果两个参数相等,返回0,如果第一个参数小于第二个参数,返回一个负数。
JDK8之前,max()方法中使用用户定义的对象,须首先通过一个类显式实现Comparator<T>接口。JDK8后,可以简单将比较方法的引用传递给max()方法,因为可以自动实现比较器。
在本程序中,MyClass既没有定义自己的比较方法,也没有实现Comparator接口。但是通过调用max()方法,仍然可以获得MyClass对象列表的最大值,这是因为UseMethodRef定义了静态方法compareMC(),他与Comparator 定义的compare()方法兼容,因此没必要显式地实现Comparator接口并创建其实例。

10.0 构造函数引用
10.1普通构造函数(非泛型)。先看代码:
package com.edpeng.game1;

interface MyFunc {
    Myclass func(int n);
}

class Myclass {
    private int val;
    //第一个构造函数
    Myclass(int v) {
            val = v;
        }

    //第二个构造函数
    Myclass() {
            val = 0;
        }

    int getVal() {
        return val;
    };
}

public class test1 {
    public static void main(String[] args) {
        MyFunc myClassCons = Myclass::new;

        Myclass mc = myClassCons.func(100);
        System.out.println("Myclass中的val为: \n" + mc.getVal());
    }
}

执行结果为:


图片.png

这里涉及到创造构造函数的引用。语法为:

classname::new
//上述实际代码中为
// Myclass::new

我们主要看几行关键代码:

  MyFunc myClassCons = Myclass::new;
  • 本程序中,MyFunc的func()方法返回MyClass类型的引用,并且有一个int类型的参数。
  • MyClass定义了两个构造函数,第一个有参(int),第二个无参。
  • Myclass::new”就是创建了对MyClass构造函数的引用的表达式,然后通过如下语句进行实例化和设置参数(int型):
MyFunc myClassCons = Myclass::new;
Myclass mc = myClassCons.func(100);
10.2 泛型构造函数。其实与非泛型没什么区别。唯一的区别在于可以指定类型参数。如下演示代码所示:
package com.edpeng.game1;


interface MyFunc<T> {
    Myclass<T> func(T n);
}

class Myclass<T> {
    private T val;
    //第一个构造函数
    Myclass(T v) {
            val = v;
        }

    //第二个构造函数
    Myclass() {
            val = null;
        }

    T getVal() {
        return val;
    };
}

public class test1 {
    public static void main(String[] args) {
        MyFunc<Integer> myClassCons = Myclass<Integer>::new;

        Myclass<Integer> mc = myClassCons.func(100);
        System.out.println("Myclass中的val为: \n" + mc.getVal());
    }
}

执行结果和10.1中一样:


图片.png

和10.1中代码内容、结构是一样的,把非泛型改成泛型而已。

10.3 像10.1和10.2只是简单说明下可以这么用,但是这么用一点好处也没有。而且两个构造函数却是相同的名字使用起来极易造成错误(很容易用错方法)。

下面这个代码案例将通过一种更加实际的用法,体现构造函数引用的好处:

package com.edpeng.game1;

interface MyFunc<R, T> {
    R func(T n);
}

class MyClass<T> {
    private T val;

    // 第一个构造函数
    MyClass(T v) {
        val = v;
    }

    // 第二个构造函数
    MyClass() {
        val = null;
    }

    T getVal() {
        return val;
    };
}

class MyClass2 {
    String str;
    // 第一个构造函数
    MyClass2(String s) {
        str = s;
    }
    // 第二个构造函数
    MyClass2() {
        str = "";
    }

    String getVal() {
        return str;
    }
}

public class test1 {
    static <R, T> R myClassFactory(MyFunc<R, T> cons, T v) {
        return cons.func(v);
    }

    public static void main(String[] args) {
        MyFunc<MyClass<Double>, Double> myClassCons = MyClass<Double>::new;
        MyClass<Double> mClass = myClassFactory(myClassCons, 100.1);

        System.out.println("Myclass中的val为: \n" + mClass.getVal());

        MyFunc<MyClass2, String> myClassCons2 = MyClass2::new;
        MyClass2 mc2 = myClassFactory(myClassCons2, "lambda");
        System.out.println("Myclass2中的str为: \n" + mc2.getVal());
    }
}

执行结果如下:


图片.png
  • 可以看到程序中使用myClassFactory()方法来创建MyClass<Double>和MyClass2类型的对象。
  • 本程序中,MyClass是泛型类,而MyClass不是,但是这两个方法都能通过myClassFactory()方法创建,因为这两个类的构造函数都与MyFunc的func()方法兼容。
  • 从本例中可以看出,构造函数引用带给了Java强大的能力。
11.0 预定义的函数式接口
11.1 作为最后一个小点,必须有点总结性的东西。

本篇和上一篇所用的案例中,基本实现定义一个自己的函数式接口。作为小案例来说这算是脱裤子放屁——多此一举。但这样目的,是为了演示lambda表达式和函数式接口背后的基本概念。

11.2 在很多时候,我们并不需要自己去定义函数式接口,因为JDK8之后,包含了新包java.util.function,其中提供了一些预定义的函数式接口。
11.3 这里简单介绍下java.util.function包下一些预定于函数式接口
接口 用途
UnaryOperator<T> 对类型为T的对象应用一元运算,并返回结果,结果类型也是T,包含方法名为apply()
BinaryOperator<T> 对类型为T的对象应用操作,并返回结果,结果类型也是T,包含方法名为apply()
Consumer<T> 对类型为T的对象应用操作,包含方法名为accept()
Supplier<T> 返回类型为T的对象,包含的方法名为get()
Function<T,R> 对类型为T的对象应用操作,并返回结果,结果类型为R的对象,包含方法名为apply()
Predicate<T> 确定类型为T的对象是否满足某种约束,并返回指出结果的布尔值,包含方法名为test()
11.4 下面演示通过function接口重写“4.0 块lambda表达式”中计算阶乘的代码:
package com.edpeng.game1;

import java.util.function.Function;

public class test1 {

    public static void main(String[] args) {
        Function<Integer, Integer> factorial = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++) {
                result = i * result;
            }
            return result;
        };
        // 3的阶乘:1*2*3
        System.out.println("3的阶乘是:" + factorial.apply(3));
        // 5的阶乘:1*2*3*4*5
        System.out.println("5的阶乘是:" + factorial.apply(5));
    }
}

在4.0中原来的源代码为:

package com.edpeng.game1;

interface Numericfunc {
    int func(int n);
}

public class test1 {

    public static void main(String[] args) {
        Numericfunc numericfunc = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++) {
                result = i * result;
            }
            return result;
        };
        // 3的阶乘:1*2*3
        System.out.println("3的阶乘是:" + numericfunc.func(3));
        // 5的阶乘:1*2*3*4*5
        System.out.println("5的阶乘是:" + numericfunc.func(5));
    }
}

两份代码执行结果是一样的:


图片.png

END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容

  • 前段时间一直在看lambda表达式,但是总感觉吃不透,在深入了解lambda表达式的时候,需要很多基础的知识栈。这...
    西瓜真好吃丶阅读 2,725评论 0 7
  • 简介 概念 Lambda 表达式可以理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主...
    刘涤生阅读 3,204评论 5 18
  • Lambda表达式 利用行为参数化这个概念,就可以编写更为灵活且可重复使用的代码。但同时,使用匿名类来表示不同的行...
    谢随安阅读 874评论 2 0
  • 转载自:《深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)》——Luci...
    琦小虾阅读 714评论 0 5
  • 时间是一只藏在黑暗中的手,在你一出神,一恍惚之间,物走星移。我们都是搭了“时光机”去远方的孩子,好多回忆都丢失在过...
    流波上的白鸟阅读 738评论 7 14