目录
一、概述
二、Lambda语法的历史
2.1 Lambda名字的含义
2.2 Lambda的历史
三、Lambda语法的核心接口
3.1 Lambda的四大核心接口
3.1.1 概述
3.1.2 Consumer 接口
3.1.3 Supplier 接口
3.1.4 Function 接口,>
3.1.5 Predicate 接口
四、Lambda的引用
4.1 概述
4.2 方法的引用
4.2.1 对象::实例方法
4.2.2 类::静态方法
4.2.3 类::实例方法
4.3 构造器的引用
4.4 数组的引用
五、Lambda的使用场景
5.1 简化编程
5.2 函数式接口
5.3 事件处理
5.4 并行处理
一、概述
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),它允许我们以简洁、可读的方式表示匿名函数。通过Lambda表达式,我们可以将代码块作为参数传递给其他函数,从而实现更灵活的编程。
二、Lambda语法的历史
2.1 Lambda名字的含义
Lambda 这个名字 并不是一个什么的缩写,它是希腊第十一个字母 λ 的读音,同时它也是微积分函数中的一个概念,所表达的意思是一个函数入参和出参定义,在编程语言中其实是借用了数学中的 λ,并且多了一点含义,在编程语言中功能代表它具体功能的叫法是匿名函数(Anonymous Function),根据百科的解释:匿名函数在计算机编程中是指一类无需定义标识符(函数名)的函数或子程序。
2.2 Lambda的历史
说起Lambda 的历史,虽然它在 JDK8 发布之后才正式出现,但是在编程语言界,它是一个具有悠久历史的东西,最早在 1958 年在Lisp 语言中首先采用,而且虽然Java脱胎于C++,但是C++在2011年已经发布Lambda 了,但是 JDK8 的 LTS 在2014年才发布,现代编程语言则是全部一出生就自带 Lambda 支持。
三、Lambda语法的核心接口
3.1 Lambda的四大核心接口
3.1.1 概述
Java8为了我们方便编程,就为我们提供了四大核心函数式接口,分别是Consumer<T> : 消费型接口、Supplier<T> : 供给型接口、Function<T, R> : 函数型接口、Predicate<T> : 断言型接口,具体如下图所示:
3.1.2 Consumer<T> 接口
代码例子:
package main.java.com.ningzhaosheng.lambada.demo;
import java.util.function.Consumer;
/**
* @author ningzhaosheng
* @date 2024/6/27 17:57:21
* @description Consumer接口 测试例子
*/
public class TestConsumer {
public static void main(String[] args) {
task(66.66,(m) -> System.out.println("本次一共花费"+m+ "元!!!"));
}
public static void task(double money, Consumer<Double> consumer){
consumer.accept(money);
}
}
3.1.3 Supplier<T> 接口
代码例子:
package main.java.com.ningzhaosheng.lambada.demo;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* @author ningzhaosheng
* @date 2024/6/27 18:03:18
* @description Supplier 接口测试例子
*/
public class TestSupplier {
public static void main(String[] args) {
List<Integer> list = getNumList(10, () -> (int) (Math.random() * 100));
for (Integer num : list) {
System.out.println("随机数:" + num);
}
}
public static List<Integer> getNumList(int num, Supplier<Integer> supplier) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < num; i++) {
Integer n = supplier.get();
list.add(n);
}
return list;
}
}
3.1.4 Function<T, R> 接口
代码例子:
package main.java.com.ningzhaosheng.lambada.demo;
import java.util.function.Function;
/**
* @author ningzhaosheng
* @date 2024/6/27 18:10:01
* @description Function 接口测试例子
*/
public class TestFunction {
public static void main(String[] args) {
String trimStr = stringHandler("\t\t\t hello,你好啊,升哥!",(str)->str.trim());
System.out.println("字符串去掉空格==========="+trimStr);
String newStr = stringHandler("桃子姑娘是一个很漂亮的姑娘,我们青梅竹马,两小无猜,我很喜欢桃子姑娘!",(str)->str.substring(26));
System.out.println("截取字符串==========="+newStr);
}
public static String stringHandler(String str, Function<String,String> function){
return function.apply(str);
}
}
3.1.5 Predicate<T> 接口
代码例子:
package main.java.com.ningzhaosheng.lambada.demo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
* @author ningzhaosheng
* @date 2024/6/27 18:21:37
* @description Predicate 接口测试例子
*/
public class TestPredicate {
public static void main(String[] args) {
List<String> list = Arrays.asList("Hello", "你好啊,升哥", "HashMap", "Python", "JDK8", "Map", "List", "Set", "Collection");
List<String> stringList = filterStr(list, (str) -> str.length() > 5);
for (String string : stringList) {
System.out.println("打印满足条件的字符串=========" + string);
}
}
public static List<String> filterStr(List<String> strings, Predicate<String> predicate) {
List<String> stringList = new ArrayList<String>();
for (String str : strings) {
if (predicate.test(str))
stringList.add(str);
}
return stringList;
}
}
四、Lambda的引用
4.1 概述
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! 方法引用:使用操作符 “ :: ” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
可以将方法引用理解为 Lambda 表达式的另外一种表现形式,方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
4.2 方法的引用
4.2.1 对象::实例方法
代码例子一:
package main.java.com.ningzhaosheng.lambada.demo1.method;
import java.io.PrintStream;
import java.util.function.Consumer;
/**
* @author ningzhaosheng
* @date 2024/6/28 10:03:20
* @description 测试对象::实例方法引用
*/
public class TestObjectAndInstanceMethod {
public static void main(String[] args) {
Consumer<String> con1 = (str)->System.out.println(str);
con1.accept("Hello World!");
PrintStream ps = System.out;
Consumer<String> con2 = ps::println;
con2.accept("Hello Java8!");
Consumer<String> con3 = System.out::println;
con3.accept("Hello Lambada!");
}
}
代码例子二:
package main.java.com.ningzhaosheng.lambada.demo1.method;
import main.java.com.ningzhaosheng.lambada.demo1.Employee;
import java.util.function.Supplier;
/**
* @author ningzhaosheng
* @date 2024/6/28 10:13:54
* @description 测试对象::实例方法引用
*/
public class TestObjectAndInstanceMethod1 {
public static void main(String[] args) {
Employee em = new Employee();
em.setAge(20);
em.setName("张三");
Supplier<? extends String> supplier = ()->em.getName();
String str = supplier.get();
System.out.println(str);
Supplier<Integer> supplier1 = em::getAge;
Integer age = supplier1.get();
System.out.println(age);
}
}
4.2.2 类::静态方法
代码例子:
package main.java.com.ningzhaosheng.lambada.demo1.method;
import java.util.Comparator;
/**
* @author ningzhaosheng
* @date 2024/6/28 10:28:20
* @description 测试类::静态方法引用
*/
public class TestClassAndStaticMethod {
public static void main(String[] args) {
Comparator<Integer> comparator = (x,y)->Integer.compare(x,y);
System.out.println(comparator.compare(10,20));
Comparator<Integer> comparator1 = Integer::compare;
System.out.println(comparator1.compare(100,300));
}
}
4.2.3 类::实例方法
代码例子:
package main.java.com.ningzhaosheng.lambada.demo1.method;
import java.util.function.BiPredicate;
/**
* @author ningzhaosheng
* @date 2024/6/28 10:34:11
* @description 测试类::实例方法引用
*/
public class TestClassAndInstanceMethod {
public static void main(String[] args) {
BiPredicate<String,String> bp1 = (str1,str2)->str1.equals(str2);
System.out.println(bp1.test("Hello","hello"));
BiPredicate<String,String> bp2 = String::equals;
System.out.println(bp2.test("Java","Java"));
}
}
4.3 构造器的引用
代码例子:
package main.java.com.ningzhaosheng.lambada.demo1.construct;
import main.java.com.ningzhaosheng.lambada.demo1.Employee;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author ningzhaosheng
* @date 2024/6/28 10:44:03
* @description 测试构造器引用
*/
public class TestConstruct {
public static void main(String[] args) {
// 无参构造
Supplier<Employee> supplier = () -> new Employee();
System.out.println(supplier.get());
// 无参构造
Supplier<Employee> supplier1 = Employee::new;
System.out.println(supplier1.get());
// 一个参数构造
Function<Integer, Employee> function = Employee::new;
Employee employee = function.apply(1001);
System.out.println(employee.toString());
// 两个参数构造
BiFunction<Integer, String, Employee> biFunction = Employee::new;
Employee employee1 = biFunction.apply(1001, "张三");
System.out.println(employee1.toString());
}
}
4.4 数组的引用
代码例子:
package main.java.com.ningzhaosheng.lambada.demo1.array;
import java.util.function.Function;
/**
* @author ningzhaosheng
* @date 2024/6/28 10:55:26
* @description 测试数组引用
*/
public class TestArray {
public static void main(String[] args) {
Function<Integer,String[]> function = (x)->new String[x];
String[] strings = function.apply(10);
System.out.println(strings.length);
Function<Integer,String[]> function1 = String[]::new;
String[] strings1 = function1.apply(50);
System.out.println(strings1.length);
}
}
五、Lambda的使用场景
通过使用Lambda表达式,我们可以写出更简洁、易读的代码,提高代码的可维护性和开发效率。下面列举一下它的使用场景。
5.1 简化编程
使用lambda表达式可以简化代码,避免定义一大堆小方法。
5.2 函数式接口
只包含一个抽象方法的接口称为函数式接口。这些接口可以使用lambda表达式。
例如:
Runnable r = () -> System.out.println("Hello, World!");
new Thread(r).start();
5.3 事件处理
在Java GUI编程中,lambda表达式经常用于按钮点击等事件的处理。
例如:
JButton button = new JButton("Click Me");
button.addActionListener(event -> System.out.println("Button clicked!"));
5.4 并行处理
Java 8的流(Stream)库使用lambda表达式来进行并行处理。
例如:
package main.java.com.ningzhaosheng.lambada.demo2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/**
* @author ningzhaosheng
* @date 2024/7/2 9:52:30
* @description 测试Java8 lambda stream
*/
public class TestLambdaStream {
public static void main(String[] args) {
// 创建一个包含一百万个随机整数的列表
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
numbers.add(ThreadLocalRandom.current().nextInt(199));
}
//顺序流的处理
long startTimeSeq = System.currentTimeMillis();
double averageSequential = numbers.stream()
.mapToInt(Integer::intValue)
.average()
.getAsDouble();
long endTimeSeq = System.currentTimeMillis();
System.out.println("sequential Average:" + averageSequential);
System.out.println("Time taken (Sequential): " + (endTimeSeq - startTimeSeq) + "ms");
//并行流的处理
long startTimePar = System.currentTimeMillis();
double averageParallel = numbers.parallelStream()
.mapToInt(Integer::intValue)
.average()
.getAsDouble();
long endTimePar = System.currentTimeMillis();
System.out.println("parallel Average: " + averageParallel);
System.out.println("Time taken (Parallel): " + (endTimePar - startTimePar) + "ms");
}
}
可以看出,顺序流和并行流得到了相同的平均值,但并行流的处理时间明显少于顺序流。因为并行流能够将任务拆分成多个小任务,并在多个处理器核心上同时执行这些任务。
当然并行流也有缺点:
- 对于较小的数据集,可能并行流更慢
- 数据处理本身的开销较大,比如复杂计算、大量IO操作、网络通信等,可能并行流更慢
- 可能引发线程安全问题
好了,本次内容就分享到这,欢迎关注本博主。如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!