一、Lambda表达式
1.1 什么是Lambda表达式?
Lambda表达式是JDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作。
Lambda表达式主要运用在将匿名内部类代码进行优化,当接口中只有且只有一个抽象方法的时候,我们可以将这个方法使用Lambda表达式进行优化
基本语法:
(参数列表)->{代码体}
1.2 省略规则
- 参数类型可以省略
- 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
- 方法只有一个参数时小括号可以省略(方法没有参数时必须加上小括号)
- 以上这些规则都记不住也可以省略不记
1.3 练习
1.3.1 创建线程时
```java // 原始写法: new Thread(new Runnable(){ @Override public void run() {
} }).start();System.out.println("Hello World");
//Lambda表达式 new Thread(() -> System.out.println(“Hello World”)).start();
<a name="glChi"></a>
### 1.3.2 IntBinaryOperator类
```java
public static int calculateNum(IntBinaryOperator operator){
int a = 10;
int b = 20;
return operator.applyAsInt(a, b);
}
// 原始写法
public static void main(String[] args) {
int i = calculateNum(new IntBinaryOperator(){
@Override
public int applyAsInt(int left,int right){
return left + right;
}
});
System.out.println("i = " + i);
}
//Lambda表达式
public static void main(String[] args) {
int i = calculateNum((int left, int right) -> {
return left + right;
});
System.out.println("i = " + i);
}
二、Stream流式编程
2.1 概念
Java8的Stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作。可以更方便的让我们对集合或数组操作。
我们可以将数组或集合转换成流来进行操作,每个流都必须要有终结操作才能被执行
2.2 创建流
2.2.1 单列集合
List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();
2.2.2 数组
Integer[] arr = {1,2,3,4,5};
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);
2.2.3 双列集合
Map<String,Integer> map = new HashMap<>();
map.put("蜡笔小新",19);
map.put("黑子",17);
map.put("日向翔阳",16);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
2.3 流的中间操作
2.3.1 filter
方法
可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。
// 例如:打印集合中姓名长度大于1的作者名字
List<Author> authors = getAuthors();
authors.stream()
.filter(author -> author.getName().length() > 1)
.forEach(author -> System.out.println(author.getName()));
//实际上,是去调用内部的test方法,我们通过匿名内部类的形式可以看出
authors.stream()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getName().length() > 1;
}
})
.forEach(item -> System.out.println(item.getName()));
2.3.2 map
方法
可以把对流中的元素进行计算或转换。实际上是调用了内部的apply()
方法,通过给Function
接口指定泛型,就可以将我们流中原来的元素类型,转换成指定类型。后续操作的就是该类型了。
List<Author> authors = getAuthors();
authors.stream()
.map(new Function<Author, String>() {
@Override
public String apply(Author author) {
return author.getName();
}
})
.forEach(item -> System.out.println(item));
通过Stream Trace
工具可以直观的感受到
我们也可以对流中的元素进行计算,例如:我们需要将集合中所有作者的年龄 + 10
List<Author> authors = getAuthors();
authors.stream()
.map( author -> author.getAge())
.map( age -> age + 10)
.forEach( item -> System.out.println(item));
2.3.3 distinct
方法
可以去除流中的重复元素。distinct
方法是依赖Object
的equals
方法来判断是否是相同对象的。所以需要注意重写equals
方法。
注意: 如果我们使用了
Lombok
插件,那么我们可以直接通过@Data
注解来帮我们生成equals
方法
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.forEach(item -> System.out.println(item.getName()));
2.3.4 sorted
方法
可以对流中的元素进行排序。
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted()
.forEach(author -> System.out.println(author.getAge()));
注意: 该方法会返回由该流的元素组成的流,按自然顺序排序。如果该流的元素不是
Comparable
,则在执行终端操作时可能会抛出java.lang.ClassCastException
, 所以我们需要在实体类对象中实现Comparable
接口,并重写compareTo()
方法
我们也可以使用这个带有参数的sorted()
方法,重写一个compare()
方法即可。
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted(((o1, o2) -> o2.getAge() - o1.getAge()))
.forEach(author -> System.out.println(author.getAge()));
2.3.5 limit
方法
可以设置流的最大长度,超出的部分将被抛弃。
List<Author> authors = getAuthors();
authors.stream()
.limit(2)
.forEach(author -> System.out.println(author));
2.3.6 skip
方法
跳过流中的前n
个元素,返回剩下的元素
List<Author> authors = getAuthors();
authors.stream()
.skip(2)
.forEach(author -> System.out.println(author));
2.3.7 flatMap
方法
map
只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(author -> System.out.println(author.getName()));