Lambda表达式
实例讲解lambda语法
- JDK8开始支持Lambda表达式,使程序编写更优雅
- 利用Lambda可以更简洁的实现匿名内部类与函数声明和调用
- 基于Lambda提供的Stream流式处理极大地简化了对于集合的操作。
下面,我们通过示例代码来看一下Lambda表达式和原始代码的区别
原始代码:
从这里不难看出,我们如果需要实现集合排序,需要通过实现Collections.sort方法来实现,而该方法的第二个参数很明显是一个匿名内部类,这样看起来代码显得臃肿,那么如果我们使用匿名内部类的方式代码又是怎样的呢?
可以看到,采用Lambda表达式之后代码精简了很多,那么Lambda表达式的语法到底是什么含义呢?我们接着往下看。
Lambda表达式语法
Lambda语法格式
基础接口:
package com.lambda.operate;
public interface MathOperation {
public Float operater(Integer a,Integer b);
}
测试用类:
package com.lambda;
import com.lambda.operate.MathOperation;
public class LambdaSample {
public static void main(String[] args) {
// 基础Lambda表达式语法
MathOperation addition = (Integer a, Integer b) -> {
System.out.println("加法运算");
return a + b + 0f;
};
System.out.println(addition.operater(5, 2));
// 可省略入参类型
MathOperation subdtruct = (a, b) -> {
System.out.println("减法运算");
return a - b + 0f;
};
System.out.println(subdtruct.operater(5, 2));
// 单行语句可省略大括号和返回return
MathOperation multiition = (a, b) ->
a * b + 0f;
;
System.out.println(multiition.operater(5, 2));
}
}
效果:
需要注意的是:我们是用Lambda表达式有一个约束条件是:
Lambda表达式只能实现有且只有一个抽象方法的接口,Java称之为"函数式接口”
基于Lambda实现函数式编程
什么是函数式编程
- 函数式编程是基于函数式接口并是用Lambda表达式的编程方式
- 函数式编程中重要的理念就是将代码作为可重用数据带入到程序运行中
- 函数式编程强调“”你想做什么”,而不是”你想怎么做”。
什么是函数式接口
- 函数式接口是有且只有一个抽象方法的接口
- Java中拥有大量的函数式接口,例如java.lang.Runnable
- JDK8后提供了一系列的函数式接口,位于java.util.function包中
函数式接口Predicate
- Predicate是新增的函数式接口,位于java.util.function
- Predicate用于测试传入的数据是否满足判断要求
- Predicate接口需要实现test()方法进行判断逻辑
Predicate接口用于做数据校验,下面给出示例代码:
package com.lambda;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateSample {
public static void main(String[] args) {
Predicate<Integer> predicate = n->n>4;
boolean result =predicate.test(5);
System.out.println(result);
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// 过滤出所有偶数
filter(list,a->a%2==0);
// 过滤出所有奇数
filter(list,a->a%2==1);
// 过滤出所有的大于5的奇数
filter(list,a->a%2==1&&a>5);
}
public static void filter(List<Integer> list,Predicate<Integer> predicate){
for (Integer num:list) {
if (predicate.test(num)){
System.out.print(num+" ");
}
}
System.out.println();
}
}
其它函数式接口
Consume函数接口适用于只有一个入参,不需要返回参数的接口类型。
Function函数接口适用于有一个输入参数并且需要返回数据的功能代码,如下图示,两个泛型分别是入参类型及返回类型
Consume函数
package com.lambda;
import java.util.function.Consumer;
public class ConsumerSample {
public static void output(Consumer<String> comsumer){
comsumer.accept("天行健,君子以自强不息");
}
public static void main(String[] args) {
output(s-> System.out.println("控制台打印: "+s));
output(s-> System.out.println("向远程机器发送: "+s));
}
}
Function函数
package com.lambda;
import java.util.Random;
import java.util.function.Function;
public class FuncionSample {
public static void main(String[] args) {
Function<Integer ,String> function =(l)->{
String str ="abcdefghijklmnopqrstuvwxyz123456789";
StringBuffer stringBuffer =new StringBuffer();
Random random = new Random();
for (int i = 0; i < l; i++) {
Integer a = random.nextInt(str.length());
stringBuffer.append(str.charAt(a));
}
return stringBuffer.toString();
};
System.out.println(function.apply(10));
System.out.println(function.apply(68));
}
}
总结
函数式接口提供了一个特殊的注解"@FunctionalInterface",通知编译器这是函数式接口,进行抽象方法检查
函数式编程和面向对象编程比较
Stream流式处理
- Stream流式处理是建立在Lambda基础上的多数据处理技术
- Stream对集合数据进行高度抽象,极大简化代码
- Stream可对集合进行迭代,去重,筛选,排序,聚合等一系列操作
Stream示例:
Stream常用方法
下面通过几个示例来学习Stream流的知识
流的创建方式【5种】
package com.Stream.code;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamGenerator {
@Test
// 1.基于数组创建
public void generator1() {
String[] arr = {"zhao", "qian", "sun", "li"};
Stream<String> stream = Stream.of(arr);
stream.forEach(s -> System.out.println(s));
}
@Test
//2.基于数组创建
public void generator2() {
List<String> arrList = Arrays.asList("zhao", "qian", "sun", "li");
Stream<String> stream = arrList.stream();
stream.forEach(s -> System.out.println(s));
}
@Test
// 3.基于generate创建无限长度流
public void generator3() {
Stream<Integer> stream = Stream.generate(()->new Random().nextInt(10000));
stream.limit(10).forEach(s -> System.out.println(s));
}
//4.基于迭代器创建流
@Test
public void generator4() {
Stream stream = Stream.iterate(1,n->n+1);
stream.limit(100).forEach(s -> System.out.println(s));
}
// 5.基于字符序列创建流
@Test
public void generator5() {
String str ="abcdefg我的";
IntStream stream =str.chars();
stream.forEach(s -> System.out.println((char)s));
}
}
流的常用方法
package com.Stream.method;
import org.junit.Test;
import org.omg.CosNaming.IstringHelper;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamMethod {
@Test
public void case1() {
// 提取所有整数偶数并求和
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
Integer sum = list.stream().mapToInt(s -> Integer.parseInt( s)).filter(n -> n % 2 == 0).sum();
System.out.println(sum);
}
// 2.所有名称首字母大写
@Test
public void case2() {
List<String> list = Arrays.asList("zhao yi","qian er","sun san","li si","zhou wu","wu liu");
List<String> newList1 = list.stream().map(s->s.substring(0,1).toUpperCase()+s.substring(1))
//.forEach(s-> System.out.println(s));
.collect(Collectors.toList());
System.out.println(newList1);
}
// 3.将所有数据按照从大到小排序
@Test
public void case3() {
List<Integer> list =Arrays.asList(1,2,5,3,6,8,10,9,5,99);
List<Integer> newList2 = list.stream().distinct().filter(n->n%2==1).sorted((a,b)->b-a).collect(Collectors.toList());
System.out.println(newList2);
}
}