什么是lambda表达式
- JDK8开始支持lambda表达式,用来让程序编写更优雅
- 利用Lambda可以更简洁的实现匿名内部类与函数声明与调用
基于lambda提供stream流式处理极大简化对集合的操作
Lambda表达式语法格式
lambda operator ```java public interface MathOperation { public Float operate(Integer a, Integer b); } //(参数列表)->实现语句
public static void main(String[] args) { //1、标准使用方式 //约束条件:Lambda表达式只能实现有且只有一个抽象方法的接口,Java中成为函数式接口 MathOperation addition = (Integer a, Integer b) -> { System.out.println(“加法运算”); return a + b + 0f; }; System.out.println( addition.operate(5, 3)); //2、lambda允许忽略参数类型 MathOperation substraction = (a, b) -> { return Float.valueOf(a - b); }; System.out.println(substraction.operate(1111, (int) 11.1)); //3、单行实现代码可以省略大括号和return MathOperation multiplication = (a, b) -> Float.valueOf(a * b); System.out.println(multiplication.operate(3, 5)); }
- 使用逗号分隔参数,参数类型可以省略,单参数括号可以省略
- 单行直接写,多行用{}包括,并且要在最后一句使用return返回结果
- 函数式接口:有且只有一个抽象方法的接口称为函数式接口,可以使用Lambda表达式快速的实现函数式接口;函数式接口和Lambda表达式两者加起来形成了函数式编程
<a name="YCQyi"></a>
## 函数式编程
- 函数式编程是基于函数式接口(有且只有一个抽象方法的接口称为函数式接口)并使用lambda表达的编程方式
- 函数式编程理念是将代码作为可重用数据带入到程序运行中
- 函数式编程强调“你想做什么”,而不是:“你想怎么做”
- Java中拥有大量的函数式接口,如Java .lang.Runnable;JDK8后提供了一系列新的函数式接口,位于java.util.funcation
- 函数式接口Predicate是新增的函数式接口,位于java.util.funcation;Predicate用于测试传入的数据是否满足判断要求;Predicate接口需要实现test()方法进行逻辑判断。
```java
/**
* 理解函数式编程
* Predicate函数式接口的使用方法
*/
public class PredicateSample {
public static void main(String[] args) {
Predicate<Integer> predicate = n -> n > 4;
System.out.println(predicate.test(2));
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//函数式编程理念是将代码作为可重用数据带入到程序运行中
filter(list, n -> n % 2 == 1); //获取所有奇数
filter(list, n -> n % 2 == 0);// 获取所有偶数
filter(list, n -> n > 5 && n % 2 == 0);//获取所有大于5的偶数
/* for (Integer integer : list) {
if (!(integer % 2 == 0)) {
System.out.println("integer = " + integer);
}
}*/
}
public static void filter(List<Integer> list, Predicate<Integer> predicate) {
for (Integer integer : list) {
if (predicate.test(integer)) {
System.out.println("integer = " + integer);
}
}
}
}
接口 | 用途 |
---|---|
Cosumer |
对应有一个输入参数无输出的功能代码 |
Function |
对应一个有输入参数且需要返回数据的功能带代码,第一个参数说明参数的类型,第二个参数说明返回值类型 |
Predicate |
用于条件判断,固定返回布尔值 |
Consumer函数式接口
/**
* Consumer接口的使用
*/
public class ConsumerSimple {
public static void main(String[] args) {
output(n -> System.out.println(n));
output(s -> {
System.out.println("向XXX网站发送数据包" + s);
});
}
public static void output(Consumer<String> consumer) {
String text = "天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱起所为";
//consumer做什么并不清楚,只有在传入参数时才决定做什么
consumer.accept(text);
}
}
Function函数式接口
/**
* 利用Function函数式编程生成定长随机字符串
*/
public class FunctionSimple {
public static void main(String[] args) {
Function<Integer, String> randomStringFunction = l -> {
String chars = "abcdefghigklmnopqrstuvwxyz0123456789";
StringBuffer stringBuffer = new StringBuffer();
Random random = new Random();
for (int i = 0; i < l; i++) {
int position = random.nextInt(chars.length());
char c = chars.charAt(position);
stringBuffer.append(c);
}
// return String.valueOf(stringBuffer);
return stringBuffer.toString();
};
String s = randomStringFunction.apply(16);
System.out.println("s = " + s);
}
}
函数式接口特殊检查注解:不满足函数式接口的要求就会报错
@FunctionalInterface //通知编译器这是函数式接口,进行抽象方法检查
public interface MathOperation {
public Float operate(Integer a, Integer b);
}
Stream流式处理
Stream流式处理是建立在Lambda基础上的多数据处理技术
- Stream对集合数据处理进行高度抽象,极大简化代码量
- Stream可对集合进行迭代、去重、筛选、排序、聚合等一系列的操作
Stream常用方法 | 接口 | 用途 | | —- | —- | | forEach | 循环遍历 | | map | map方法用于映射每个元素到对应的结果 | | filter | filter方法用于通过设置的条件过滤出元素 | | limit | limit方法用于获取指定数量的流 | | sorted | sorted方法用于对流进行排序 | | Collectors | Collectors类实现将流转换成集合和聚合元素 |
Stream流的五种创建方式:后三种不常用,了解即可
// 基于数组进行创建
@Test
public void generator1() {
String[] arr = {"Lily", "Andy", "Jackson", "Smith"};
Stream<String> stream = Stream.of(arr);
stream.forEach(s -> System.out.println(s));
}
//基于集合进行创建
@Test
public void generator2() {
List<String> list = new ArrayList<>();
list.add("Lily");
list.add("Andy");
list.add("Jackson");
list.add("Smith");
Stream<String> stream = list.stream();
stream.forEach(s -> System.out.println(s));
}
//利用generator方法创建无限长度流
@Test
public void generator3() {
Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(100000));
// stream.forEach(s -> System.out.println(s));
stream.limit(10).forEach(s -> System.out.println(s));
}
//基于迭代器创建流;使用stream代替创痛的for循环;尽管如此使用较少
@Test
public void generator4() {
Stream<Integer> stream = Stream.iterate(1, n -> n + 1);
stream.limit(10).forEach(s -> System.out.println(s));
}
//基于字符序列创建流
@Test
public void generator5() {
String string = "abcdefg我的";
IntStream stream = string.chars();
stream.forEach(c -> System.out.println((char) c));
}
Stream常用方法
//提取集合中所有偶数并对其进行求和操作
@Test
public void case1() {
List<String> list = Arrays.asList("1", "2", "3", "4", "5", "6");
Stream<String> stream = list.stream();//获取stream对象
int sum = stream.mapToInt(s -> Integer.parseInt(s)) //mapToInt将流中每一个数据转换为整数
.filter(n -> n % 2 == 0)// filter对流数据进行过滤
.sum();// 求和
System.out.println("sum = " + sum);
}
//所有名字首字母大写
@Test
public void case2() {
List<String> list = Arrays.asList("lily", "smith", "jackson");
List<String> newList = list.stream()
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1))//按指定的规则对每一个流数据进行转换,转换的结构仍然保存在当前的流中,无法对外进行输出
// .forEach(s -> System.out.println("s = " + s));
.collect(Collectors.toList());//collect 对流数据进行收集,生成新的List/Set(set会自动取出重复元素)
System.out.println("newList = " + newList);
}
//将所有奇数从大到小进行排序,且不允许出现重复
@Test
public void case3() {
List<Integer> list = Arrays.asList(2,3,2,44,33,67,23);
List<Integer> newList = list.stream()
.distinct() //去除重复的流数据
.filter(n -> n % 2 == 1)
.sorted((a, b) -> b - a) // 需要传入compare方法的实现,前一个参数代表前一个数据数据,
.collect(Collectors.toList());
System.out.println("newList = " + newList);
}