目录
一、概述
二、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操作、网络通信等,可能并行流更慢
- 可能引发线程安全问题
好了,本次内容就分享到这,欢迎关注本博主。如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!