IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Lambda表达式详解 -> 正文阅读

[移动开发]Lambda表达式详解

1. 几个例子

场景:现在要对一些苹果进行分类,可以按颜色分,也可以按重量分
一种实现如下:

package test;

import java.util.ArrayList;
import java.util.List;

class Apple{
	String color;
	double weight;
	public Apple(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}
interface FilterApple{
	public boolean test(Apple apple);
}

//筛选红色苹果
class FilterAppleByColor implements FilterApple{

	@Override
	public  boolean test(Apple apple) {
		return apple.color.equals("red");
		
	}
	
}

//筛选重量大于50g的苹果
class FilterAppleByWeight implements FilterApple{

	@Override
	public  boolean test(Apple apple) {
		return apple.weight>50;
		
	}
	
}
public class LambdaDemo {
	public static void filterApple(List<Apple> apples,FilterApple filter) {
		for(Apple apple:apples)
		{
			if(filter.test(apple))
				System.out.println(apple);
		}
	}
	public static void main(String[] args) {
		Apple apple1=new Apple("red",50);
		Apple apple2=new Apple("red",100);
		Apple apple3=new Apple("green",50);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		System.out.println("红色苹果:");
		FilterApple fByColor=new FilterAppleByColor();
		filterApple(apples, fByColor);
		System.out.println("重量>50g的苹果");
		FilterApple fByWeight=new FilterAppleByWeight();
		filterApple(apples, fByWeight);
		
		
		
	}
}

在这里插入图片描述

当然也可以使用匿名类实现:

package test;

import java.util.ArrayList;
import java.util.List;

class Apple{
	String color;
	double weight;
	public Apple(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}
interface FilterApple{
	public boolean test(Apple apple);
}
public class LambdaDemo {
	public static void filterApple(List<Apple> apples,FilterApple filter) {
		for(Apple apple:apples)
		{
			if(filter.test(apple))
				System.out.println(apple);
		}
	}
	public static void main(String[] args) {
		Apple apple1=new Apple("red",50);
		Apple apple2=new Apple("red",100);
		Apple apple3=new Apple("green",50);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		System.out.println("红色苹果:");
		filterApple(apples, new FilterApple() {
			
			@Override
			public boolean test(Apple apple) {
				return apple.color.equals("red");
			}
		});
		System.out.println("重量>50g的苹果");
		filterApple(apples, new FilterApple() {
			
			@Override
			public boolean test(Apple apple) {
				return apple.weight>50;
			}
		});
			
	}
}

上面两个代码的问题在于,代码冗余量较大
第一份代码中: 根据颜色分类的话要实现一个接口,根据重量分类的话也要实现一个接口
第二份代码中:虽然使用了匿名类,本质上还是实现了接口,假设需要多次按颜色分类,就会产生大量的重复代码

Lambda表达式改进

package test;

import java.util.ArrayList;
import java.util.List;

class Apple{
	String color;
	double weight;
	public Apple(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}
interface FilterApple{
	public boolean test(Apple apple);
}
public class LambdaDemo {
	public static void filterApple(List<Apple> apples,FilterApple filter) {
		for(Apple apple:apples)
		{
			if(filter.test(apple))
				System.out.println(apple);
		}
	}
	public static void main(String[] args) {
		Apple apple1=new Apple("red",50);
		Apple apple2=new Apple("red",100);
		Apple apple3=new Apple("green",50);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		System.out.println("红色苹果:");
		filterApple(apples, (Apple a)->a.color.equals("red"));
		System.out.println("重量>50g的苹果");
		filterApple(apples, (Apple a)->a.weight>50);
			
	}
}

上面的代码将匿名类换成了Lambda表达式


2. Lambda表达式概念

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式

几个特点:

  1. 匿名:不像普通的方法那样有一个明确的名称:写得少而想得多!
  2. 函数:Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表
  3. 传递:Lambda表达式可以作为参数传递给方法或存储在变量中
  4. 简洁:无需像匿名类那样写很多模板代码

再使用一个例子熟悉Lambda表达式,现在需要按重量对苹果进行排序,Collectios.sort(collectios,comparator) 这个方法可以进行排序,可以传入一个Comparator根据我们的需要按自定义类的某个属性排序

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Apple{
	String color;
	double weight;
	public Apple(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}
interface FilterApple{
	public boolean test(Apple apple);
}
public class LambdaDemo {
	public static void filterApple(List<Apple> apples,FilterApple filter) {
		for(Apple apple:apples)
		{
			if(filter.test(apple))
				System.out.println(apple);
		}
	}
	public static void main(String[] args) {
		Apple apple1=new Apple("red",50);
		Apple apple2=new Apple("red",25);
		Apple apple3=new Apple("green",75);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		Comparator<Apple> comparator=new Comparator<Apple>() {

			@Override
			public int compare(Apple o1, Apple o2) {
				if(o1.weight>o2.weight)
					return 1;
				else if(o1.weight<o2.weight){
					return -1;
				}else {
					return 0;
				}
			}
		};
		System.out.println("排序前:");
		for(Apple apple:apples)
			System.out.println(apple);
		
		Collections.sort(apples,comparator);
		
		System.out.println("排序后:");
		for(Apple apple:apples)
			System.out.println(apple);
		
		
	}
}

在这里插入图片描述

下面改用匿名类实现Comparator接口

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Apple{
	String color;
	double weight;
	public Apple(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}
interface FilterApple{
	public boolean test(Apple apple);
}
public class LambdaDemo {
	public static void filterApple(List<Apple> apples,FilterApple filter) {
		for(Apple apple:apples)
		{
			if(filter.test(apple))
				System.out.println(apple);
		}
	}
	public static void main(String[] args) {
		Apple apple1=new Apple("red",50);
		Apple apple2=new Apple("red",25);
		Apple apple3=new Apple("green",75);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		
		System.out.println("排序前:");
		for(Apple apple:apples)
			System.out.println(apple);
		
		Collections.sort(apples,new Comparator<Apple>() {

			@Override
			public int compare(Apple o1, Apple o2) {
				return o1.weight-o2.weight>0?1:-1;
			}
		});
		
		System.out.println("排序后:");
		for(Apple apple:apples)
			System.out.println(apple);
		
		
	}
}

再使用Lambda表达式:

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Apple{
	String color;
	int weight;
	public Apple(String color, int weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}

public class LambdaDemo {
	
	public static void main(String[] args) {
		Apple apple1=new Apple("red",25);
		Apple apple2=new Apple("red",20);
		Apple apple3=new Apple("green",75);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		
		System.out.println("排序前:");
		for(Apple apple:apples)
			System.out.println(apple);
		Collections.sort(apples,(Apple o1,Apple o2)->o1.weight-o2.weight);
		System.out.println("排序后:");
		for(Apple apple:apples)
			System.out.println(apple);
		
		
	}
}

下面这些都是有效的Lambda表达式:

  • ()-> {} :这个Lambda没有参数,并返回void。它类似于主体为空的方法:publicvoid run() {}
  • ()-> "Raoul":这个Lambda没有参数,并返回String作为表达式
  • ()-> {return "Mario"; }:这个Lambda没有参数,并返回String(利用显式返回语句)

在这里插入图片描述

下面这些都是无效的Lambda表达式:

  • (Integer i)-> return "Alan"+i;:return是一个控制流语句。要使此Lambda有效,需要使花括号,如下所示:(Integer i)-> {return "Alan"+i; }
  • (String s)-> {"IronMan"; } :“Iron Man”是一个表达式,不是一个语句。要使此Lambda有效,你可以去除花括号和分号,如下所示:(String s)-> "Iron Man"。或者如果你喜欢,可以使用显式返回语句,如下所示:(String s)->{return "IronMan"; }

3. 函数式接口

可以在函数式接口上使用Lambda表达式
函数式接口就是只定义一个抽象方法的接口
只有一个抽象方法

在这里插入图片描述

Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例

匿名类和Lambda的比较:
在这里插入图片描述


4. 使用函数式接口

1. 函数式接口Predicate
java.util.function.Predicate接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}
package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class LambdaDemo {

// 过滤集合中为空串的字符串
	public static void filter(List<String> strs,Predicate<String> predicate) {
		for(String str:strs)
		{
			if(predicate.test(str))
				System.out.println(str);
		}
	}
	public static void main(String[] args) {
		
		Predicate<String> notEmpty=(String s)->!s.isEmpty();//定义过滤规则
		List<String> strs=new ArrayList<>();
		strs.addAll(Arrays.asList("apple","banana","","orange",""));
		System.out.println(strs);
		filter(strs, notEmpty);
		
	}
}

在这里插入图片描述

2. 函数式接口Consumer
java.util.function.Consumer定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void)

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

}
package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

public class LambdaDemo {
	public static <T> void forEach(List<T> list,Consumer<T> consumer) {
		for(T x:list)
			consumer.accept(x);
	}
	public static void main(String[] args) {
		
		forEach(Arrays.asList(1,2,3,4,5), (Integer i)->System.out.println(i));
	}
}


在这里插入图片描述

3. 函数式接口Function
java.util.function.Function<T, R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}
package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

public class LambdaDemo {
	
	//输入一个字符串集合  返回每个字符串对应的长度
	public static <T,R> List<R> getStrLens(List<T> list,Function<T, R> f) {
		List<R> result=new ArrayList<>();
		for(T x:list)
			result.add(f.apply(x));
		return result;
				
	}
	public static void main(String[] args) {
		
		
		List<Integer> strLens=new ArrayList<>();
		strLens=getStrLens(Arrays.asList("apple","banana","orange"), (String s)->s.length());
		System.out.println(strLens);
		
	}
}

在这里插入图片描述

任何函数式接口都不允许抛出受检异常(checked exception)。如果你需要Lambda表达式来抛出异常,有两种办法:定义一个自己的函数式接口,并声明受检异常,或者把Lambda包在一个try/catch块中
在这里插入图片描述在这里插入图片描述


5. 类型检查、类型推断以及限制

1. 类型检查

例子:使用Predicate函数式接口,按重量筛选苹果

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}
package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
class Apple{
	String color;
	double weight;
	public Apple(String color, double weight) {
		super();
		this.color = color;
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Apple [color=" + color + ", weight=" + weight + "]";
	}
}
public class LambdaDemo {
	// 过滤集合中为空串的字符串
		public static <T> void filter(List<T> list,Predicate<T> predicate) {
			for(T x:list)
			{
				if(predicate.test(x))
					System.out.println(x);
			}
		}
	public static void main(String[] args) {
		
		
		Apple apple1=new Apple("red",50);
		Apple apple2=new Apple("red",25);
		Apple apple3=new Apple("green",75);
		Apple apple4=new Apple("green",100);
		List<Apple> apples=new ArrayList<>();
		apples.add(apple1);
		apples.add(apple2);
		apples.add(apple3);
		apples.add(apple4);
		Predicate<Apple> big=(Apple apple)->apple.weight>50;//定义过滤规则
		filter(apples, big);
		
	}
}

在这里插入图片描述

2. 同样的Lambda,不同的函数式接口
同一个Lambda可用于多个不同的函数式接口:
在这里插入图片描述

3. 类型推断

Predicate<Apple> big=(Apple apple)->apple.weight>50;
可以改写为:
Predicate<Apple> big=apple->apple.weight>50;
在这里插入图片描述

4. 使用局部变量

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
public static void main(String[] args) {
			int portNum=8080;
			Runnable r=()->System.out.println(portNum);
			new Thread(r).start();
	}

在这里插入图片描述

注意:局部变量必须显式声明为final,或事实上是final
在这里插入图片描述
在这里插入图片描述

Local variable portNum defined in an enclosing scope must be final or effectively final

为什么Lambda表达式引用局部变量有final限制?

在上面代码中,主线程中给portNum分配了栈内存,存在这种情况:如果新创建的线程运行了很长时间,此时主线程中的portNum变量已经被回收了,此时新创建的线程又要使用portNum变量。Java在访问自由局部变量时,实际上是在访问它的副本,而不是访问原始变量。主线程中的原始变量portNum没有了,新线程中的副本portNum还有,但如果portNum只被赋值一次就没有什么影响了,因此就有了这个限制

其次在lambda表达式内部不允许修改外围定义的局部变量的值可以保证多线程情况下的安全


6. 方法引用

方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们
在这里插入图片描述

方法引用主要有三类:

  1. 指向静态方法的方法引用(例如Integer的parseInt方法,写作Integer::parseInt)
  2. 指向任意类型实例方法的方法引用(例如String的length方法,写作String::length)
  3. 指向现有对象的实例方法的方法引用
    在这里插入图片描述

代码示例:

public class LambdaDemo {
		
	public static void main(String[] args) {
		
		List<String> strs=Arrays.asList("a","b","A","B");
		strs.sort((s1,s2)->s1.compareToIgnoreCase(s2));
		System.out.println(strs);//[a, A, b, B]
	}
}

使用方法引用后如下:

public class LambdaDemo {
		
	public static void main(String[] args) {
		
		List<String> strs=Arrays.asList("a","b","A","B");
		strs.sort(String::compareToIgnoreCase);
		System.out.println(strs);//[a, A, b, B]
	}
}

参考:
《Java 8实战》

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 00:13:15  更:2022-04-01 00:13:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 20:02:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码