轻松掌握Lambda表达式

一、产生

Java1.8的新特性,也是最主要的特性,允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

二、Lambda出世原因

先看一个例子:

  @Test
    void testLambdaThread(){
       // 匿名内部类
        Runnable runnable= new Runnable(){
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        // 启动一个线程去执行
        new Thread(runnable).start();
    }

这里首先创建了一个匿名内部类Runnable,这个匿名内部类有且只有一个执行方法run(),我们覆盖了方法体,如果不是匿名内部类,我们需要自己去写一个实现类,这样是不是很麻烦,代码繁杂;

那我们可以想象一下,这个接口如果是某一个函数(假设函数为A)的参数,而这个接口,只有一个方法(实现类只需要重写这个方法),我们可不可以直接往A的参数里写这个方法体,函数便可以识别该接口的方法并执行(由编译器去帮我们编译产生相同效果的class)。

于是上述线程可使用lambda表达式:

new Thread(()-> System.out.println("hello world"));

三、Lambda表达式语法

(parameters) -> expression
或
(parameters) ->{ statements; }
一些参数   一个箭头	   一段代码
标准格式:
(参数类型 参数名称) ‐> { 代码语句 }
  • parameters 顾名思义,方法体的参数,这里可无需声明参数类型,如果是一个参数,可省略括号();

    p->p.getId();
    (Person a ,Person b)->a.getSalary().compareTo(b.getSalary())
    
  • expression 如果执行方法体较为简单,使用一个表达式即可! 省略{};

  • statements 如方法体实现代码量较多,实现逻辑使用{};

上面应该不难理解,这是语法,接下来实操

1.无参无返回

见上线程的lambda表达式

2. 有参有返回(重点分析)

下面举例演示java.util.Comparator 接口的使用场景代码,其中的抽象方法定义为:

public abstract int compare(T o1, T o2);
当需要对一个对象数组进行排序时, Arrays.sort 方法需要一个Comparator 接口实例来指定排序的规则。

上代码

public class Person {
	private String name;
	private int age;
}

传统写法

import java.util.Arrays;
import java.util.Comparator;
public class Demo06Comparator {
	public static void main(String[] args) {
		Person[] array = {
		new Person("叶存星福", 29),
		new Person("李春华", 31),
		new Person("叶海祥", 60) };
		// 匿名内部类
		Comparator<Person> comparator = new Comparator<Person>() {
			@Override
			public int compare(Person people1, Person people2) {
			return people1.getAge() ‐ people2.getAge();
		}};
		Arrays.sort(array, comparator ); // comparator 为 Comparator接口实例
		for (Person person : array) {
			System.out.println(person);
		}
	}
}

分析

  • 为了排序, Arrays.sort 方法需要排序规则,即Comparator 接口的实例,抽象方法compare 是关键;
  • 为了指定compare 的方法体,不得不需要Comparator 接口的实现类;
  • 为了省去定义一个ComparatorImpl 实现类的麻烦,不得不使用匿名内部类;
  • 必须覆盖重写抽象compare 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;
    实际上,只有参数和方法体才是关键。

Lambda表达式

Arrays.sort(array, (Person a, Person b) ‐> {
	return a.getAge() ‐ b.getAge();
});
for (Person person : array) {
	System.out.println(person);
}

3.无参有返回

与上述几乎一致,上代码:

/**
 * @author yecxf
 * @created time 2020/10/17 10:11
 */
public interface Invocation {
    // 唯一获取结果方法
    Object getResult();
}

接口作为另一方法的入参

/**
 * @author yecxf
 * @created time 2020/10/17 10:13
 */
public class CacheOperator {

    public Object doCache(String key,Integer ExpireTime,Invocation invocation){
        /**
         * 假设这里是存储缓存操作
         */
        return null;
    }
}

Dao层或Service层返回结果入缓存

 public ResultInfo getNpsInfo(){
         cacheOperator.doCache("helloLambda",10*60,()->npsDao.getNpsInfo());
         return null;
     }

四、使用Lambda表达式条件

  1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的Runnable 、Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。

  2. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

五、实际应用场景

1. List集合使用场景

新建一个list

	NpsInfo npsInfo = new NpsInfo("北京银行", (float) 458484845415L);
    NpsInfo npsInfo1 = new NpsInfo("深圳银行", (float) 4584848451415L);
    NpsInfo npsInfo2 = new NpsInfo("工商银行", (float) 45848484445415L);
    NpsInfo npsInfo3 = new NpsInfo("建设银行", (float) 45848544845415L);
      
	List<NpsInfo> npsInfoList = new ArrayList<NpsInfo>(){{
		    add(npsInfo); 
		    add(npsInfo1); 
		    add(npsInfo2); 
		    add(npsInfo3); 
	 }};
  • 遍历
// 遍历操作
npsInfoList.parallelStream().forEach(p-> System.out.println(p.getDepartmentName()));
//等价于
npsInfoList.parallelStream().forEach((NpsInfo nps)-> System.out.println(nps.getDepartmentName()));
  • 过滤
// 过滤操作
List<NpsInfo> filterNpsInfos = npsInfoList.parallelStream().filter(p -> "深圳银行".equals(p.getDepartmentName())).collect(Collectors.toList());
filterNpsInfos.forEach(p-> System.out.println(p.getDepartmentName()));
  • 排序
// 排序操作
List<NpsInfo> sortedNpsInfo = 	npsInfoList.parallelStream().sorted(Comparator.comparing(NpsInfo::getDepartmentScore)).collect(Collectors.toList());
sortedNpsInfo.forEach(p-> System.out.println(p.getDepartmentName()));
  • 校验
// 校验, 符合返回true
boolean b = npsInfoList.parallelStream().allMatch(p -> "hello world".equals(p.getDepartmentName()));
  • 某个字段存放到Set集合中
- // 存放到Set集合中
Set<Float> npsInfoScoreSet = npsInfoList.parallelStream().map(p -> p.getDepartmentScore()).collect(Collectors.toSet());
Iterator<Float> iterator = npsInfoScoreSet.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}

2. Json格式数据

实际开发中有这种场景,请求接口成功后,需对返回数据做校验,成功后才会给到前端,如何快速校验呢;

JSONArray和List功能一致,记住就OK~

// 模拟接口返回
public static String getRequest(List<NpsInfo> list){
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("responseCode","000000");
        hashMap.put("msg","返回成功");
        hashMap.put("data", JSONArray.toJSONString(list));
        return JSONArray.toJSONString(hashMap);
    }
// 过滤
 // 假设这是请求成功返回的数据
String responseDada = getRequest(npsInfoList);
JSONObject jsonObject = (JSONObject) JSON.parse(responseDada);
String data = (String) jsonObject.get("data");
JSONArray jsonArray = (JSONArray) JSONArray.parse(data);
List<JSONObject> departmentName = jsonArray.parallelStream().map(p -> (JSONObject) p).filter(p -> "深圳银行".equals(p.getString("departmentName"))).collect(Collectors.toList());

版权声明:本文为ye1714505125原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。