Java8 Lamdba表达式 003

本文通过实例讲解了Java8中Lambda表达式的应用,包括集合元素的过滤、传统Runnable接口的Lambda实现、匿名内部类的替代以及Lambda作为参数传递等高级特性。

继续lamdba,上篇Java8 Lamdba表达式 002讲了使用lamdba对集合元素进行排序,本篇讲述使用lamdba对集合元素过滤,示例代码沿用上篇:

001

public class SortingPlayer {
	
	public static void main(String[] args) {
		List<Player> playerList = new ArrayList<>();
		playerList.add(new Player("Black", "White", 9));
		playerList.add(new Player("John", "Hello", 2));
		playerList.add(new Player("Machicel", "Jackson", 7));
		playerList.add(new Player("Ani", "Hessius", 4));
		playerList.add(new Player("Mark", "Towns", 3));
		playerList.add(new Player("Huge", "Nana", 6));
	}
}

class Player{
	//类定义参考上篇
}
如001所示 创建一个集合 并在集合中添加几条元素。名字,分数。现在要对集合中的元素进行过滤,比如我要获取所有分数大于等于5的元素把它们放到另一个集合中,打印出符合条件的元素个数。

002

/**
 * Specifying Filter Criteria on a Collection of Data
 */
List<Player> bigGoals = new ArrayList<>();
playerList.stream().filter(
		p -> p.getGoals() >= 5)
		.forEach(element -> bigGoals.add(element));
System.out.println("Number of Players Matching Criteria: " + bigGoals.size());
002中新建一个集合用来保存符合条件的元素,使用stream由于它包含易用的过滤功能。根据playerList生成stream然后在上面调用过滤功能,过滤的处理使用了lamdba表达式。lamdba表达式传递一个Player对象作为参数,然后根据条件goals>=5进行过滤,如果符合则往新建的集合添加这个元素。


通过以上的学习,我们应该对lamdba表达式有着深刻的印象了,它声明一个功能接口,也就是只有一个抽象方法的接口,并用lamdba表达式实现。或者使用Function<argument,return>定义,并实现。在传统的Java类中,也有着只有一个抽象方法的接口,比如新建一个线程java.util包下的Runnable接口,它里面只有一个run抽象方法。现在我们考虑使用lamdba表达式实现Runnable接口,并跟传统的实现进行比较。

003

public class RunnableCompare {
	
	public static void main(String[] args) {
		Runnable oldRunnable = new Runnable() {
			@Override
			public void run() {
				int x = 5 * 3;
				System.out.println("The variable using the old way equals: " + x);
			}
		};
		Runnable lambdaRunnable = () -> {
			int x = 5 * 3;
			System.out.println("The variable using the lambda equals: " + x);
		};
		oldRunnable.run();
		lambdaRunnable.run();
	}
}
由于java.util.Runnable是一个功能接口,实现接口之类的样板式的代码可以使用lamdba替换。Runnable里的抽象方法是无参数所以 参数列表是一对空的括号().
Runnable assignment = () -> {expression or statements};

如果你写过JavaSE的界面或者写过Android的代码,你可能会知道点击一个按钮的时候时候处理的方法里面有定义一个匿名的内部类,并对其中的方法进行实现,来处理按钮点击触发的动作。接下来我们讲讲如何用lamdba表达式来取代这个繁冗的内部类实现代码。

003

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;


public class ReplacingAnonymousInnerClasses {
	
	public static void main(String[] args) {
		Button btn = new Button();
		/**
		 * typical 
		 */
		btn.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				System.out.println("Do something... typical");
			}
		});
		/**
		 * lambda
		 */
		btn.setOnAction(e ->{
			System.out.println("Do something... lambda");
		});
	}

}
003示例中:我们定义了一个按钮,为按钮btn设置点击事件。setOnAction,里面对按钮点击操作处理。新建一个匿名类,然后实现其中的handle方法,非常复杂,而接下来的示例中看到我们可以使用lamdba轻松搞定。

Lamdba表达式还能作为参数传递到方法中使用;

比如我要计算一个集合List<Double>每个元素的乘积,通过以上的学习我们我们可以很容易的写出这个功能:

004

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class Test {

	private static Double multiplyNum = 1d;

	public static void main(String[] args) {
		
		Function<List<Double>, Double>  multiply = doubleList -> {
			doubleList.stream().forEach(num -> multiplyNum *= num);
			return multiplyNum;
		};
		List<Double> list = new ArrayList<>();
		list.add(12.3);
		list.add(25.6);
		list.add(38.4);
		multiply.apply(list);
		System.out.println(multiplyNum.intValue());
	}

}
ps:上面使用Function定义了Lamdba表达式用以计算集合元素的乘积,这里有一点注意,如果 multiplyNum定义在Main中,而不是在类的局部变量,那这里就会报错,Lamdba中在一个封闭范围内的变量必须是final或者表现是final的,你不能更改它的值。

Ok,写好了计算的方法,我们定义一个函数用以接收一个Lamdba表达式,以及要计算的元素集,然后返回计算的结果,方法如下:

005

public Double calculate(Function<List<Double>, Double> f1,Double[] args){
	Double returnValue;
	List<Double> varList = new ArrayList<>();
	int idx = 0;
	while (idx < args.length){
		varList.add(args[idx]);
		idx++;
	}
	returnValue = f1.apply(varList);
	return returnValue;
}
接下来加上Lamdba的实现并测试吧!

public class PassingLambdaFunctions {

	public Double calculate(Function<List<Double>, Double> f1,Double[] args){
		//见005,此处省略
	}
	
	public static void main(String[] args) {
		double x = 16.0;
		double y = 30.0;
		double z = 4.0;
		Function<List<Double>, Double> volumeCalc = list -> {
			if (list.size() == 3) {
				return list.get(0) * list.get(1) * list.get(2);
			} else {
				return Double.valueOf("-1");
			}
		};
		Double[] argList = new Double[3];
		argList[0] = x;
		argList[1] = y;
		argList[2] = z;
		Function<List<Double>, Double> areaCalc = list -> {
			if (list.size() == 2) {
				return list.get(0) * list.get(1);
			} else {
				return Double.valueOf("-1");
			}
		};
		Double[] argList2 = new Double[2];
		argList2[0] = x;
		argList2[1] = y;
		PassingLambdaFunctions p1 = new PassingLambdaFunctions();
		System.out.println("The volume is: " + p1.calculate(volumeCalc, argList));
		System.out.println("The area is: " + p1.calculate(areaCalc, argList2));
	}

}
任何类型的功能都可以使用Lamdba实现然后传递给不同的对象使用。这样可以更加提高代码的复用性&可维护性。Lamdba就讲到这。如果不觉得这些还不能满足你的需求,可以到官网去查找更详情的代码,或者搜索你想要的内容。

ps:本文示例引自 Josh Juneau所著 Java 8 Recipes, 2nd Edition
mission completed!
O(∩_∩)O~

<think>好的,我现在需要处理用户关于Java Lambda表达式使用条件和示例的问题。用户希望了解Lambda表达式的使用条件以及具体的示例。首先,我要回忆一下Lambda表达式的基本概念和相关知识,然后整理出清晰的回答结构。 首先,Lambda表达式是在Java 8中引入的,它允许以更简洁的方式实现函数式接口。根据之前的引用内容,用户提供的资料提到Lambda表达式替代了接口的实现类和匿名内部类,这说明Lambda的使用必须与函数式接口相关。 接下来,用户的问题明确提到了使用条件和示例。使用条件方面,我需要确定以下几点:接口类型必须是函数式接口(即只有一个抽象方法),参数类型需要匹配,以及Lambda的上下文依赖目标类型推断。这些要点需要逐一解释清楚,确保用户明白为什么需要这些条件。 然后是示例部分。用户提供的引用中有一些示例代码,比如使用Lambda实现Test接口,并在main方法中调用。我需要参考这些示例,并可能扩展更多的例子,比如带参数的接口、返回值的情况等,以展示不同的用法。此外,Lambda的不同写法(如省略参数类型、省略花括号等)也是需要说明的,这能帮助用户理解如何简化代码。 另外,用户提供的引用中提到了Lambda的语法形式:(params) -> expression、(params) -> statement、(params) -> { statements }。这应该在示例中体现出来,比如展示不同情况下的写法差异。 还需要注意引用文献的标注,比如在提到接口必须只有一个抽象方法时,引用用户提供的资料中的例子。例如,引用[^2]中的Test接口就是一个只有一个抽象方法的函数式接口,所以可以在这里添加引用标识。 可能还需要提到Java内置的函数式接口,如Runnable、Comparator等,但用户提供的资料中没有涉及,所以可能需要避免超出引用范围,或者简要提及但主要基于用户提供的例子。 在组织回答结构时,应该先介绍使用条件,分点列出,每一点简明扼要,并附上示例代码。然后再给出不同场景的示例,每个示例对应不同的使用情况,如无参数、带参数、带返回值等。每个示例后可以解释代码的结构,并引用相关的资料部分。 需要确保所有代码示例正确,并且符合Java语法。例如,用户提供的示例中,Test接口的Lambda实现是否正确,是否在main方法中正确调用。此外,要注意Lambda表达式只能用于函数式接口,所以在每个示例中都必须确保接口符合条件。 最后,在相关问题部分,根据用户的问题生成相关的问题,比如Lambda表达式与匿名内部类的区别、方法引用的使用等,这些都能帮助用户进一步学习。 现在需要检查是否有遗漏的条件或示例,比如异常处理、变量作用域等,但根据用户提供的引用,可能这些内容不在当前讨论范围内,所以可能不需要涉及。保持回答紧扣用户的问题和使用提供的引用资料。 总结一下,回答的结构应该是: 1. 使用条件: a. 函数式接口 b. 参数类型匹配 c. 上下文推断 2. 示例: a. 无参数示例 b. 带参数示例 c. 返回值示例 d. 简化写法示例 每个部分都要结合用户提供的引用内容,正确标注引用标识,并确保代码正确性。</think>### Java Lambda表达式使用条件与示例 #### 一、Lambda表达式的使用条件 1. **仅适用于函数式接口** Lambda表达式只能用于实现**仅包含一个抽象方法**的接口(即函数式接口)。例如,以下接口`Test`仅有一个抽象方法`test()`,因此可以使用Lambda表达式实现[^2]: ```java interface Test { public void test(); } ``` 2. **参数类型必须匹配** Lambda表达式的参数列表需与接口方法的参数类型一致。例如,若接口方法为`void run(int a, String b)`,Lambda表达式需定义为`(a, b) -> { ... }`。 3. **依赖上下文推断类型** Lambda表达式需要明确的上下文(如变量赋值、方法参数传递)来推断目标接口类型。例如: ```java Test test = () -> System.out.println("test"); // 根据变量类型Test推断 ``` --- #### 二、Lambda表达式示例 1. **无参数、无返回值的接口** ```java // 接口定义 interface Runnable { void run(); } // Lambda实现 Runnable task = () -> System.out.println("执行任务"); task.run(); ``` 2. **带参数的接口** ```java // 接口定义 interface Calculator { int calculate(int a, int b); } // Lambda实现加法 Calculator add = (a, b) -> a + b; System.out.println(add.calculate(3, 5)); // 输出8 ``` 3. **带返回值且多行代码的接口** ```java // 接口定义 interface Validator { boolean check(String input); } // Lambda实现(检查字符串长度) Validator validator = input -> { if (input.length() >= 6) return true; else return false; }; System.out.println(validator.check("hello")); // 输出false ``` 4. **简化写法** - **省略参数类型**:由上下文自动推断。 ```java Calculator multiply = (a, b) -> a * b; ``` - **单行代码省略花括号和`return`**: ```java Calculator subtract = (a, b) -> a - b; ``` --- #### 三、注意事项 - 若接口有多个抽象方法,Lambda表达式无法使用。例如,以下接口因包含两个方法会报错: ```java interface InvalidInterface { void method1(); void method2(); // 违反函数式接口规则 } ``` - Lambda表达式可访问外部局部变量,但要求变量为`final`或等效不可变[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值