/**PageBeginHtml Block Begin **/ /***自定义返回顶部小火箭***/ /*生成博客目录的JS 开始*/ /*生成博客目录的JS 结束*/

lambda 表达式

第一节: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

posted @ 2022-04-30 21:21  一品堂.技术学习笔记  阅读(70)  评论(0编辑  收藏  举报