1.Stream流
1.1两种获取流的方法
java.util.stream.Stream 是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)
获取一个流非常简单,有以下几种常用的方式:
所有的 Collection 集合都可以通过 stream 默认方法获取流;
Stream 接口的静态方法 of 可以获取数组对应的流。
根据Collection获取流
import java.util.*;importjava.util.stream.Stream;public classDemo04GetStream {public static voidmain(String[] args) {
List list = new ArrayList<>();//...
Stream stream1 =list.stream();
Set set = new HashSet<>();//...
Stream stream2 =set.stream();
Vector vector = new Vector<>();//...
Stream stream3 = vector.stream();
}
}
根据Map获取流importjava.util.HashMap;importjava.util.Map;importjava.util.stream.Stream;public classDemo05GetStream {public static voidmain(String[] args) {
Map map = new HashMap<>();//...
Stream keyStream =map.keySet().stream();
Stream valueStream =map.values().stream();
Stream> entryStream =map.entrySet().stream();
}
}
根据数组获取流
如果使用的不是集合或映射而是数组,由于数组对象不可能添加默认方法,所以 Stream 接口中提供了静态方法
of ,使用很简单:importjava.util.stream.Stream;public classDemo06GetStream {public static voidmain(String[] args) {
String[] array= { "张无忌", "张翠山", "张三丰", "张一元"};
Stream stream =Stream.of(array);
}
1.2常用方法
流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方
法均为延迟方法。)
终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样的链式调
用。本小节中,终结方法包括 count 和 forEach 方法。
逐一处理void forEach(Consumer super T>action);
过滤
Stream filter(Predicate super T>predicate);
映射 Stream map(Function super T, ? extends R>mapper);
统计个数longcount();
取用前几个
Stream limit(longmaxSize);
跳过前几个
Stream skip(longn);
组合static Stream concat(Stream extends T> a, Stream extends T> b)
1.3练习:集合元素处理
现在有两个 ArrayList 集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以
下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。
2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中。
3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。
4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。
5. 将两个队伍合并为一个队伍;存储到一个新集合中。
6. 根据姓名创建 Person 对象;存储到一个新集合中。
7. 打印整个队伍的Person对象信息。
两个队伍(集合)的代码如下:
importjava.util.ArrayList;
而 Person 类的代码为:importjava.util.List;public classDemoArrayListNames {public static voidmain(String[] args) {//第一支队伍
ArrayList one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("石破天");
one.add("石中玉");
one.add("老子");
one.add("庄子");
one.add("洪七公");//第二支队伍
ArrayList two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("赵丽颖");
two.add("张三丰");
two.add("尼古拉斯赵四");
two.add("张天爱");
two.add("张二狗");//....
}
}
而 Person 类的代码为:
public classPerson {privateString name;publicPerson() {}publicPerson(String name) {this.name =name;
}
@OverridepublicString toString() {return "Person{name='" + name + "'}";
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}
}
解答:
importjava.util.ArrayList;importjava.util.List;importjava.util.stream.Stream;public classDemoStreamNames {public static voidmain(String[] args) {
List one = new ArrayList<>();//...
List two = new ArrayList<>();//...//第一个队伍只要名字为3个字的成员姓名;//第一个队伍筛选之后只要前3个人;
Stream streamOne = one.stream().filter(s ‐> s.length() == 3).limit(3);//第二个队伍只要姓张的成员姓名;//第二个队伍筛选之后不要前2个人;
Stream streamTwo = two.stream().filter(s ‐> s.startsWith("张")).skip(2);//将两个队伍合并为一个队伍;//根据姓名创建Person对象;//打印整个队伍的Person对象信息。
Stream.concat(streamOne, streamTwo).map(Person::new).forEach(System.out::println);
}}
运行效果:
Person{name='宋远桥'}
Person{name='苏星河'}
Person{name='石破天'}
Person{name='张天爱'}
Person{name='张二狗'}
2.方法引用
在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿什么参数做什么操作。那么考虑
一种情况:如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑?
双冒号 :: 为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方
法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。
2.1 通过对象名引用成员方法
2.2 通过类名称引用静态方法
2.3 通过super引用成员方法
2.4 通过this引用成员方法
2.5 类的构造器引用
2.6 数组的构造器引用