第一节:lambda 表达式简介



MyNumber

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing1;

/**
*
* @author Alan_Liu
*
*
* 函数式接口:
* 函数式接口是仅指定了 一个抽象方法的接口。
*
* 只有当没有指定默认实现时,接口方法才是抽象方法。
* 即:没有指定默认实现的接口方法隐式地是抽象方法,所以没有必须要使用abstract修饰符。
*
*/
//函数式接口 其功能由getValue定义的
interface MyNumber {
double getValue(); //隐式抽象方法 且也是唯一方法。
/**
* lambda表达式不是独立执行的。而是构建了一个函数式接口定义的抽象方法的实现。
* 该函数式接口定义了它的目标类型。
* 结果:只有在定义了lambda表达式的目标类型的上下文中,才能使用该表达式。
* 当把一个lambda表达式赋给一个函数式接口引用时,就创建了这样的上下文。其他目标类型上下文包括变量初始化,return语句和方法参数等。
* 如:
* MyNumber myNum;
* myNum = () -> 123.45;
*
* 当目标类型上下文中出现lambda表达式时,会自动创建实现了 函数式接口的 一个类的实例。函数式接口声明的抽象方法的行为由lambda表达式定义。当通过目标
* 调用该方法是,就会执行lambda表达式,因此 lambda 表达式提供了一种将代码片段转换为对象的方法。
* 因此,lambda表达式成了getValue()方法的实现。
* System.out.println("A fixed value: " + myNum.getValue());
*
*/

}



LambdaDemo

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing1;
/**
*
* @author Alan_Liu
*
*
* lambda 表达式简介:
* 理解lambda 表达式的java实现:
* 一:lambda表达式自身
* 二:函数式接口
*
* lambda 表达式本质上就是一个匿名(未命名)方法。这个方法不是独立执行的。而是用于实现由函数式接口定义的另一个方法。
* 因此,lambda表达式会导致产生一个匿名类。lambda表达式也常称为闭包。
*
* 函数式接口是仅包含一个抽象方法的接口。一般来说,这个方法指明了接口的目标用途。因此,函数式接口通常表示单个动作。
* 例如:标准接口Runnable 是一个函数式接口,因为它只定义了一个方法run()。因此,run()定义了Runnable的动作。
* 函数式 接口定义了lambda表达式的目标类型。
*
*
* lambda表达式的基础知识
* lambda 表达式在java语言中引入了一个新的语法 元素和操作符。 这个操作符是 ->,即称之为 lambda操作符或者箭头操作符。
* () -> 123.45
* lambda表达式需要的所有参数 -> lambda体,即lambda表达式要执行的动作。
* 可以把 -> 表达成“成了” 或者“进入”
*
* java 定义了两种lambda体。
* 一种包含单独一个表达式
* 一种包含一个代码块
*
*
*
*
*
*/
class LambdaDemo {
/**
* @param args
*/
public static void main(String args[]) {
MyNumber myNum; // declare an interface reference

// Here, the lambda expression is simply a constant expression.
// When it is assigned to myNum, a class instance is
// constructed in which the lambda expression provides an override
// of the getValue() method in MyNumber.
/**
* 这个 lambda 表达式没有参数,所以参数列表为空。它返回常量值为123.45.
*
*/
myNum = () -> 123.45;
/**
* 因此这个表达式的作用类似于下面的方法:
double MyMeth() {
return 123.45;
}
当然 lambda表达式定义的方法没有名称。
*/

// Call getValue(), which is overridden by the previously assigned
// lambda expression.
System.out.println("A fixed value: " + myNum.getValue());

// Here, a more complex expression is used.
/**
* 这个lambda 表达式使用了 Math.random() 获取一个伪随机数,将其乘以100 然后返回结果。
* 这个lambda表达式也不需要参数
*/
myNum = () -> Math.random() * 100;

// These call the lambda expression in the previous line.
System.out.println("A random value: " + myNum.getValue());
System.out.println("Another random value: " + myNum.getValue());

/**
* (n) ->(n%2)==0
* 如果参数N的值是偶数,这个lambda 表达式会返回true,尽管可以显式指定参数的类型,例如本列中的n,但是通常不需要这么做。
* 因为很多时候,参数的类型是可以推断出来的。于命名方法 一样,lambda表达式可以指定需要用到的任意数量的参数。
*/

/**
* lambda表达式必须兼容功能接口定义的方法。因此,这不会工作:
*/
// A lambda expression must be compatible with the method
// defined by the functional interface. Therefore, this won't work:
/**
* lambda 表达式必须 与其想要的实现的抽象方法兼容。
* 因此,下面该行代码必须注释掉。因为此行代码是非法的
* 因为String类型的值与double类型不兼容,而 getValue()的方法类型是double.
*/
// myNum = () -> "123.03"; // Error!


}
}



第二节:演示:如何使用带参数的lambda表达式


NumericTest

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing2;

//Demonstrate a lambda expression that takes a parameter.

//Another functional interface.
interface NumericTest {
boolean test(int n);
}


LambdaDemo2

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing2;

/**
*
* @author Alan_Liu
*
* 该实例只要演示:如何使用带参数的lambda表达式
*
*
*/
class LambdaDemo2 {
public static void main(String args[]) {
// A lambda expression that tests if a number is even.
/*
* 特别要注意下面该行测试奇偶性的lambda表达式:
* (n) -> (n % 2) == 0;
* 注意,这里没有指定N的类型,相反 n的类型是从上下文推断出来的。本列中,其类型是
* 从NumericTest接口定义的test()方法的参数类型推断出来的。而该参数的类型是 int.
* 在lambda表达式中,也可以显式指定参数的类型。
* 如:(int n) -> (n % 2) == 0;
* 其中 n被显式指定为int类型。通常没有必要显式指定类型,但是在需要的时候是可以指定的。
*
* 关于lambda 表达式的另外一个重要的地方:
* 函数式接口引用可以用来执行任何与其兼容的lambda表达式。注意:程序中定义了两个不同的lambda表达式,
* 他们都与函数式接口 NumericTest 的test() 方法兼容。
* 第一个 isEven,用于确定值是否是偶数,
* 第二个 isNonNeg 用于检查值是否为非负值。
* 两种情况下都会测试参数n的值,
* 因为每个lambda表达式都与 test()兼容,所以都可以通过NumericTest 引用执行。
*/
NumericTest isEven = (n) -> (n % 2) == 0;

if (isEven.test(10)) {
System.out.println("10 is even");
}
if (!isEven.test(9)) {
System.out.println("9 is not even");
}


// Now, use a lambda expression that tests if a number
// is non-negative.
NumericTest isNonNeg = (n) -> n >= 0;

if (isNonNeg.test(1)) {
System.out.println("1 is non-negative");
}
if (!isNonNeg.test(-1)) {
System.out.println("-1 is negative");
}
}
/*
* ==================执行结果==================================
* 10 is even
* 9 is not even
* 1 is non-negative
* -1 is negative
*
*/
}


第三节:lambda 表达式:     测试一个数字是否是另外一个数字的因子


NumericTest2

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing3;

//Demonstrate a lambda expression that takes two parameters.
/**
*
* @author Alan_Liu
*
* lambda 表达式:
* 测试一个数字是否是另外一个数字的因子
*
*/
interface NumericTest2 {
boolean test(int n, int d);
}

LambdaDemo3

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing3;
/**
*
* @author Alan_Liu
*
* lambda 表达式:
* 测试一个数字是否是另外一个数字的因子
*
*/
class LambdaDemo3 {
public static void main(String args[]) {
// This lambda expression determines if one number is
// a factor of another.
NumericTest2 isFactor = (n, d) -> (n % d) == 0;

if (isFactor.test(10, 2))
System.out.println("2 is a factor of 10");

if (!isFactor.test(10, 3))
System.out.println("3 is not a factor of 10");
}
/**
* =======执行结果==============================
* 2 is a factor of 10
* 3 is not a factor of 10
* 在这个程序中,函数式接口NumericTest2 定义了test()方法
* boolean test(int n, int d);
* 在这个版本里。test()方法指定了两个参数, 因此 与test()方法兼容的lambda表达式也必须指定两个参数,
* 注意指定这种lambda表达式的方式:
* (n, d) -> (n % d) == 0;
* 两个参数n和d在参数列表中指定,并使用逗号分隔开。可以把这个例子推而广之。
* 每当需要一个以上的参数时,就在lambda操作符的左侧,使用一个带括号的参数列表指定参数,参数之间使用逗号分隔开。
* 对于lambda表达式 中多个参数,有一点十分重要:如果需要显示声明一个参数的类型,
* 例如:下面的代码是合法的 :
* (int n,int d) -> (n % d) == 0;
* 但是下面的不合法:
* (int n, d) -> (n % d) == 0;
*/
}



第四节:块 lambda 表达式


NumericFunc

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing4;

//A block lambda that computes the factorial of an int value.
/**
*
* @author Alan_Liu
*
* 块 lambda 表达式
*
*
*/
interface NumericFunc {
int func(int n);
}


BlockLambdaDemo

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing4;
/**
*
* @author Alan_Liu
*
* 表达式 lambda
* 如:(n, d) -> (n % d) == 0; 的lambda 体包含单个表达式,被称之为 lambad表达式体。或者 表达式lambda。
* 在表达式中,操作符右侧的代码必须包含单独一个表达式。
*
* 块 lambda 表达式
* lambda 表达式 其中 右侧的代码可以由一个代码块构成,其中可以包含多条语句。这种类型的lambda体被称之为块体。具有块体的lambda表达式有时候称之为 块lambda。
* 块lambda表达式内部可以处理的操作类型,因为它允许lambda体包含多条 语句,
* 例如:在块lambda中,可以声明变量,是用循环,指定if和swith语句,创建嵌入式代码块等。
* 创建lambda很容易,只需要使用花括号包围lambda体,就像创建其他语句块一样。
*
* 块lambda中必须显示使用return语句来返回值。
*
*/
class BlockLambdaDemo {
public static void main(String args[]) {

// This block lambda computes the factorial of an int value.
NumericFunc factorial = (n) -> {
/**
* 在 该块lambda 中声明了变量 result,使用了一个for循环,并且具有一条return语句。
* 在块lambda 体内,这么做事合法的。块lambda体在本质上 与方法体类似。
* 另外一点,当lambda 表达式中出现return 语句时,只是从lambda体返回,而不会导致包围lambda体的方法返回。
*
*/
int result = 1;

for (int i = 1; i <= n; i++)
result = i * result;

return result;
};

System.out.println("The factoral of 3 is " + factorial.func(3));
System.out.println("The factoral of 5 is " + factorial.func(5));
}
/**
*
* =========执行结果============================
* The factoral of 3 is 6
* The factoral of 5 is 120
*
*
*
*/
}


第五节:块lambda   表达式 示例


StringFunc

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing5;

//A block lambda that reverses the characters in a string.

interface StringFunc {
String func(String n);
}

BlockLambdaDemo2


package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing5;
/**
*
* @author Alan_Liu
*
* 块lambda 表达式 示例:
* 颠倒一个字符串中的字符
*
*/
class BlockLambdaDemo2 {
public static void main(String args[]) {

// This block lambda that reverses the charactrers in a string.
StringFunc reverse = (str) -> {
String result = "";
int i;

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

return result;
};
System.out.println("Lambda reversed is " + reverse.func("Lambda"));
System.out.println("Expression reversed is " + reverse.func("Expression"));
}
/**
* ======执行结果==============
* Lambda reversed is adbmaL
* Expression reversed is noisserpxE
*
*/
}



第六节:泛型函数式接口

SomeFunc

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing6;

//Use a generic functional interface with lambda expressions.

//A generic functional interface.
/**
*
* @author Alan_Liu
*
* @param <T>
*
* 泛型函数式接口:
* lambda 表达式自身不能指定类型参数。
* 因此,lambda表达式不能是泛型(当然,由于存在类型推断,所有的lambda表达式都展现出一些类似于泛型的特征。)
* 然而 与lambda表达式关联的函数式接口可以是泛型。
* 此时,lambda表达式的目标类型部分由声明函数式接口引用时指定参数类型决定。
* 为了理解函数式接口的值,考虑这样的情况,前一节的两个示例使用两个不同的函数接口,
* 一个叫做NumericFunc 另外一个叫做StringFunc 。
* 但是,两个接口都定义了一个叫做func()方法,该方法接受一个参数,返回一个结果。
* 对于第一个接口,func()方法的参数类型和返回类型为int。
* 对与第二个 接口,func() 方法参数类型和返回类型是String。因此,两个方法的唯一区别是他们需要的数据类型。
* 相较于使用两个函数式接口,他们的方法只是在需要的数据类型方面存在区别,也可以只声明一个泛型接口来处理两种情况。
* 下面演示了这种方法:
*
*/
interface SomeFunc<T> {
T func(T t);
}


GenericFunctionalInterfaceDemo

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing6;
/**
*
* @author Alan_Liu
*
* @param <T>
*
* 泛型函数式接口:
* lambda 表达式自身不能指定类型参数。
* 因此,lambda表达式不能是泛型(当然,由于存在类型推断,所有的lambda表达式都展现出一些类似于泛型的特征。)
* 然而 与lambda表达式关联的函数式接口可以是泛型。
* 此时,lambda表达式的目标类型部分由声明函数式接口引用时指定参数类型决定。
* 为了理解函数式接口的值,考虑这样的情况,前一节的两个示例使用两个不同的函数接口,
* 一个叫做NumericFunc 另外一个叫做StringFunc 。
* 但是,两个接口都定义了一个叫做func()方法,该方法接受一个参数,返回一个结果。
* 对于第一个接口,func()方法的参数类型和返回类型为int。
* 对与第二个 接口,func() 方法参数类型和返回类型是String。因此,两个方法的唯一区别是他们需要的数据类型。
* 相较于使用两个函数式接口,他们的方法只是在需要的数据类型方面存在区别,也可以只声明一个泛型接口来处理两种情况。
* 下面演示了这种方法:
*
*/
class GenericFunctionalInterfaceDemo {
public static void main(String args[]) {

// Use a String-based version of SomeFunc.
SomeFunc<String> reverse = (str) -> {
String result = "";
int i;

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

return result;
};

System.out.println("Lambda reversed is " + reverse.func("Lambda"));
System.out.println("Expression reversed is " + reverse.func("Expression"));
/*
*=====执行结果==========================
* Lambda reversed is adbmaL
* Expression reversed is noisserpxE
*/

// Now, use an Integer-based version of SomeFunc.
SomeFunc<Integer> factorial = (n) -> {
int result = 1;

for (int i = 1; i <= n; i++)
result = i * result;

return result;
};

System.out.println("The factoral of 3 is " + factorial.func(3));
System.out.println("The factoral of 5 is " + factorial.func(5));
/*
*=====执行结果==========================
* The factoral of 3 is 6
* The factoral of 5 is 120
*/

}
}


第七节:作为参数传递lambda 表达式


StringFunc

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing7;

//Use lambda expressions as an argument to a method.
/**
*
* @author Alan_Liu
*
* 作为参数传递lambda 表达式:
* lambda表达式可以使用在任何提供了目标类型的上下文中。一种情况就是作为参数表达式lambda表达式。
* 事实上,这是lambda表达式的 一种常见用途。另外,这也是lambda表达式的一种强大 用途。
* 因为可以将可执行代码作为参数传递给方法。这极大的强化了java的表达式。
* 为将lambda表达式作为参数传递,接受lambda表达式的参数的类型必须是与该lambda表达式兼容的函数接口的类型。
* 虽然使用lambda表达式作为参数十分直观,但是使用例子进行 演示仍然会有帮助。
*
*
*/
interface StringFunc {
String func(String n);
}


LambdasAsArgumentsDemo

package com.alanliu.Java8BasicCodeStuding.Java8BasciCode.Unit15_Lambda.listing7;
/**
*
* @author Alan_Liu
*
* 作为参数传递lambda 表达式:
* lambda表达式可以使用在任何提供了目标类型的上下文中。一种情况就是作为参数表达式lambda表达式。
* 事实上,这是lambda表达式的 一种常见用途。另外,这也是lambda表达式的一种强大 用途。
* 因为可以将可执行代码作为参数传递给方法。这极大的强化了java的表达式。
* 为将lambda表达式作为参数传递,接受lambda表达式的参数的类型必须是与该lambda表达式兼容的函数接口的类型。
* 虽然使用lambda表达式作为参数十分直观,但是使用例子进行 演示仍然会有帮助。
*
*
*/
class LambdasAsArgumentsDemo {

// This method has a functional interface as the type of
// its first parameter. Thus, it can be passed a reference to
// any instance of that interface, including the instance created
// by a lambda expression.
// The second parameter specifies the string to operate on.
/*
* 在该程序中,首先需要注意stringOp()方法,它有2个参数,
* 第一个参数的类型是 StringFunc , 而 StringFunc 是一个函数式接口。因此,这个参数可以接受对任何StringFunc实例的引用, 包括由lambda表达式创建的实例。
* 第二个参数是String 类型,也就是要操作的字符串。
*/
static String stringOp(StringFunc sf, String s) {
return sf.func(s);
}

public static void main(String args[]) {
String inStr = "Lambdas add power to Java";
String outStr;

System.out.println("Here is input string: " + inStr);
/*
* =========执行结果:=====================
* Here is input string: Lambdas add power to Java
*/

// Here, a simple expression lambda that uppercases a string
// is passed to stringOp( ).
/*
* 接下来:注意对stringOp() 的第一次调用,如代码所示:
*
*/
outStr = stringOp((str) -> str.toUpperCase(), inStr);
System.out.println("The string in uppercase: " + outStr);
/*这里传递了一个简单的表达式lambda作为参数,这会参建函数式接口StringFunc的 一个实例,并作为对该实例的 一个
* 引用传递给stringOp()方法的第一个参数。这就把嵌入在一个类实例中的lambda表达式传递给了方法。
* 目标类型上下文由参数的类型决定。因此lambda表达式与该类型兼容,调用时合法的。
* 在方法调用内嵌入表达式只使用一次时。
*
* =========执行结果:=====================
* The string in uppercase: LAMBDAS ADD POWER TO JAVA
*/

// This passes a block lambda that removes spaces.
/**
* 接下来:程序向StringOp()传递了一个块lambda。这个lambda表达式删除字符串中的空格。
* 如下所示:
*/
outStr = stringOp((str) -> {
String result = "";
int i;
for (i = 0; i < str.length(); i++) {
if (str.charAt(i) != ' ') {
result += str.charAt(i);
}
}
return result;
}, inStr);

System.out.println("The string with spaces removed: " + outStr);
/*
* 虽然这里使用了一个块lambda,但是传递过程与刚才讨论的传递简单的表达式lambda相同。但是,在本例子中,
* 一些程序员可以发现语法有些笨拙。
* 当块lambda看上去特别长,不适合嵌入到方法调用中时,很容易把块lambda赋给一个函数式接口变量,正如前面的几个例子
* 中所做的那样。然后,可以简单地把该引用传递给方法。
* =========执行结果:=====================
* The string with spaces removed: LambdasaddpowertoJava
*/

// Of course, it is also possible to pass a StringFunc instance
// created by an earlier lambda expression. For example,
// after this declaration executes, reverse refers to a
// synthetic instance of StringFunc.
/**
*该部分演示的内容如下:
* 先定义一个颠倒字符串的块lambda,然后把该块lambda赋给reverse.reverse是一个对StringFunc实例的引用。
* 因此,并传入reverse和要操作的字符串。
* 因为计算每个lambda表达式得到的实例是StringFunc实现。所以可以用作StringOp()方法的第一个参数。
*
*/
StringFunc reverse = (str) -> {
String result = "";
int i;

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

return result;
};

// Now, reverse can be passed as the first parameter to stringOp()
// since it refers to a StringFunc object.
System.out.println("The string reversed: " + stringOp(reverse, inStr));
/*
* =========执行结果:=====================
* The string reversed: avaJ ot rewop dda sadbmaL
*/

}
}


源码下载


源码下载地址:​​https://gitee.com/Alan2022/Java8CodeStuding​

​https://gitee.com/Alan2022/Java8CodeStuding.git​

为人:谦逊、激情、博学、审问、慎思、明辨、 笃行

学问:纸上得来终觉浅,绝知此事要躬行

为事:工欲善其事,必先利其器。

态度:道阻且长,行则将至;行而不辍,未来可期

转载请标注出处!