Java基础之lambda表达式
Lambda表达式
文章目录
lambda 表达式
-
Lambda 表达式,也称为闭包,是推动 Java 8 发布的最重要新特性
- Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)
- 使用 Lambda 表达式可以使代码变的更加简洁紧凑
-
lambda 表达式的语法格式如下:
(parameters) -> expression ; (parameters) ->{ statements; };
重要特征
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
@FunctionalInterface //定义接口时添加该注解表示函数式接口
new Thread( //将lambda表达式作为参数传入方法,构建线程对象
() -> {
int a = 0;
while(a < 10){
System.out.println(++a);
}
}
).start();
/**
(): 函数式接口中唯一抽象方法的参数;参数类型自动匹配, 可指定,只有一个参数时可忽略()
然后跟 -> {}
方法体{ }:表示方法中的具体实现,仅一句实现语句可省略{}
*/
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
- Lambda 表达式主要用来定义行内执行的方法类型接口
- 例如简单方法接口
- Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力
函数式接口
-
函数式接口(
Functional Interface
)是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口-
函数式接口可以被隐式转换为 lambda 表达式
-
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上
-
JDK 1.8 之前已有的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
-
JDK 1.8 新增加的函数接口:
java.util.function
:包含了很多类,用来支持 Java的 函数式编程
-
功能型函数式接口
- 有参数接收和返回
- Function类,例如:
@FunctionalInterface
public interface Function<T,R>{
public R apply(T t);//接受一个参数,返回一个参数;通过方法引用实现操作
/* 例如
Function<String , Boolean> fun = "www.aaa" :: startsWith;
boolean result = fun.apply("www"); //结果为true
*/
}
消费型函数式接口
- 只能进行数据的处理,没有参数返回,例如:
@FunctionalInterface
public interface Consumer<T>{
void accept(T t);//只进行数据处理,没有返回值
/*
Consumer con = System.out :: println;
con.accept("张三"); //输出张三
*/
}
供给型函数接口
- 无接受参数,有返回值
@FunctionalInterface
public interface Supplier<T>{
public T get();
/*
Supplier<String> sup = "asd" :: toUpperCase;
String str = sup.get(); // 将asd 转为大写
*/
}
断言型函数接口
- 进行判断处理
@FunctionalInterface
public interface Predicate<T>{
public Boolean test(T t);
/*
Predicate<String> pre = "asd" :: equals;
boolen result = sup.test("asd"); // 结果为true
*/
}
方法引用
- 方法引用通过方法的名字来指向一个方法
- 方法引用可以使语言的构造更紧凑简洁,减少冗余代码
- 方法引用使用一对冒号
::
//静态方法:类名称 :: static方法名称;
String :: valueOf;
//引用某个实例对象的方法:instance::method
实例化对象 :: 普通方法;
//引用特定类型方法:Class::method
特定类 :: 普通方法;
//引用构造方法:Class::new,或者更一般的Class< T >::new
类名称 :: new;
Stream
Stream
意义
-
Java 8 API添加了一个新的抽象称为流Stream,以一种声明的方式处理数据。
- 将要处理的元素集合看作一种流,
- 流在管道中传输, 可以在管道的节点上进行处理,
- 比如筛选, 排序,聚合等
- 元素流在管道中经过中间操作(intermediate operation)的处理
- 最后由最终操作(terminal operation)得到前面处理的结果
- 将要处理的元素集合看作一种流,
-
Stream(流):一个来自数据源的元素队列并支持聚合操作
-
元素是特定类型的对象,形成一个队列
Java
中Stream
并不会存储元素,而是按需计算。
-
数据源:流的来源
- 可以是集合,数组,I/O channel,产生器 generator 等
-
聚合操作:类似SQL语句一样的操作
- 比如 filter, map, reduce, find, match, sorted 等
-
-
Stream操作还有两个基础的特征
-
Pipelining:中间操作都会返回流对象本身
- 多个操作可以串联成一个管道, 如同流式风格
- 可以对操作进行优化, 比如延迟执行(laziness)和短路(short-circuiting)
- 多个操作可以串联成一个管道, 如同流式风格
-
内部迭代:Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现
- 通过Iterator或者For-Each方式显式的在集合外部进行迭代叫做外部迭代
-
strema执行流程
- 执行
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
- 转为
Java
代码
List<Integer> transactionsIds =
widgets.stream()
.filter(b -> b.getColor() == RED)
.sorted((x,y) -> x.getWeight() - y.getWeight())
.mapToInt(Widget::getWeight)
.sum();
生成流
在 Java 8 中, 集合接口有两个方法来生成流:
- stream():为集合创建串行流。
- parallelStream():为集合创建并行流。
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
forEach
-
Stream 提供了
forEach
’迭代流中的每个数据 -
// 使用 forEach 输出了10个随机数 Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
map
-
map 方法用于映射每个元素到对应的结果
-
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); // 获取对应的平方数 List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
-
filter
方法用于通过设置的条件过滤出元素 -
// 使用 filter 方法过滤出空字符串 List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取空字符串的数量 long count = strings.stream().filter(string -> string.isEmpty()).count();
limit
-
limit 方法用于获取指定数量的流
-
// 用 limit 方法打印出 10 条数据 Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
sorted
-
sorted 方法用于对流进行排序
-
Random random = new Random(); // 使用 sorted 方法对输出的 10 个随机数进行排序 random.ints().limit(10).sorted().forEach(System.out::println);
并行(parallel)程序
-
parallelStream 是流并行处理程序的代替方法
-
// 使用 parallelStream 来输出空字符串的数量 List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取空字符串的数量 long count = strings.parallelStream().filter(string -> string.isEmpty()).count(); // 可以很容易的在顺序运行和并行直接切换
Collectors
-
Collectors 类实现了很多归约操作
- 例如将流转换成集合和聚合元素
- Collectors 可用于返回列表或字符串:
-
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 获取过滤后的非空字符串集合 List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("筛选列表: " + filtered); // 获取过滤后的非空字符串集合并使用 , 拼接为字符串 String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("合并字符串: " + mergedString);
统计
-
产生统计结果的收集器主要用于int、double、long等基本类型上
- 可用来产生类似如下的统计结果
-
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("列表中最大的数 : " + stats.getMax()); System.out.println("列表中最小的数 : " + stats.getMin()); System.out.println("所有数之和 : " + stats.getSum()); System.out.println("平均数 : " + stats.getAverage());
完整实例
public class Teste {
public static void main(String args[]){
System.out.println("Java 7: ");
// 计算空字符串
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("列表: " +strings); // 列表: [abc, , bc, efg, abcd, , jkl]
long count = getCountEmptyStringUsingJava7(strings);
System.out.println("空字符数量为: " + count); // 空字符数量为: 2
count = getCountLength3UsingJava7(strings);
System.out.println("字符串长度为 3 的数量为: " + count); // 字符串长度为 3 的数量为: 3
// 删除空字符串
List<String> filtered = deleteEmptyStringsUsingJava7(strings);
System.out.println("筛选后的列表: " + filtered); // 筛选后的列表: [abc, bc, efg, abcd, jkl]
// 删除空字符串,并使用逗号把它们合并起来
String mergedString = getMergedStringUsingJava7(strings,", ");
System.out.println("合并字符串: " + mergedString); // 合并字符串: abc, bc, efg, abcd, jkl
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取列表元素平方数
List<Integer> squaresList = getSquares(numbers);
System.out.println("平方数列表: " + squaresList); //平方数列表: [9, 4, 49, 25]
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
System.out.println("列表: " +integers); // 列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
System.out.println("列表中最大的数 : " + getMax(integers)); // 列表中最大的数 : 19
System.out.println("列表中最小的数 : " + getMin(integers)); // 列表中最小的数 : 1
System.out.println("所有数之和 : " + getSum(integers)); // 所有数之和 : 85
System.out.println("平均数 : " + getAverage(integers)); // 平均数 : 9
System.out.print("随机数: ");
// 输出 10 个随机数
Random random = new Random();
for(int i=0; i < 10; i++){
System.out.print(random.nextInt() + " "); // 随机数: -3 -963 44 -10 -88 2215 -1101 576 -104 164
}
System.out.println("Java 8: ");
System.out.println("列表: " +strings); // 列表: [abc, , bc, efg, abcd, , jkl]
count = strings.stream().filter(string->string.isEmpty()).count();
System.out.println("空字符串数量为: " + count); // 空字符串数量为: 2
count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("字符串长度为 3 的数量为: " + count); // 字符串长度为 3 的数量为: 3
filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选后的列表: " + filtered); // 筛选后的列表: [abc, bc, efg, abcd, jkl]
mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString); // 合并字符串: abc, bc, efg, abcd, jkl
squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
System.out.println("Squares List: " + squaresList); // Squares List: [9, 4, 49, 25]
System.out.println("列表: " +integers); // 列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax()); // 列表中最大的数 : 19
System.out.println("列表中最小的数 : " + stats.getMin()); // 列表中最小的数 : 1
System.out.println("所有数之和 : " + stats.getSum()); // 所有数之和 : 85
System.out.println("平均数 : " + stats.getAverage()); // 平均数 : 9.444444444444445
System.out.println("随机数: ");
random.ints().limit(10).sorted().forEach(System.out::println); // 随机数: -174 -130 -12 -779 136 555 124 12649 147 170
// 并行处理
count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("空字符串的数量为: " + count); // 空字符串的数量为: 2
}
// 计算空字符串 Java7
private static int getCountEmptyStringUsingJava7(List<String> strings){
int count = 0;
for(String string: strings){
if(string.isEmpty()){
count++;
}
}
return count;
}
// 长度为 3 的字符串数量
private static int getCountLength3UsingJava7(List<String> strings){
int count = 0;
for(String string: strings){
if(string.length() == 3){
count++;
}
}
return count;
}
// 删除空字符串
private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
List<String> filteredList = new ArrayList<String>();
for(String string: strings){
if(!string.isEmpty()){
filteredList.add(string);
}
}
return filteredList;
}
// 删除空字符串并使用 , 拼接字符串
private static String getMergedStringUsingJava7(List<String> strings, String separator){
StringBuilder stringBuilder = new StringBuilder();
for(String string: strings){
if(!string.isEmpty()){
stringBuilder.append(string);
stringBuilder.append(separator);
}
}
String mergedString = stringBuilder.toString();
return mergedString.substring(0, mergedString.length()-2);
}
// 获取列表元素平方数
private static List<Integer> getSquares(List<Integer> numbers){
List<Integer> squaresList = new ArrayList<Integer>();
for(Integer number: numbers){
Integer square = new Integer(number.intValue() * number.intValue());
if(!squaresList.contains(square)){
squaresList.add(square);
}
}
return squaresList;
}
// 获取列表中最大值
private static int getMax(List<Integer> numbers){
int max = numbers.get(0);
for(int i=1;i < numbers.size();i++){
Integer number = numbers.get(i);
if(number.intValue() > max){
max = number.intValue();
}
}
return max;
}
// 获取列表中最小值
private static int getMin(List<Integer> numbers){
int min = numbers.get(0);
for(int i=1;i < numbers.size();i++){
Integer number = numbers.get(i);
if(number.intValue() < min){
min = number.intValue();
}
}
return min;
}
// 列表中元素求和
private static int getSum(List numbers){
int sum = (int)(numbers.get(0));
for(int i=1;i < numbers.size();i++){
sum += (int)numbers.get(i);
}
return sum;
}
// 获取列表中元素平均数
private static int getAverage(List<Integer> numbers){
return getSum(numbers) / numbers.size();
}
}