- Stream流
说到Stream便容易想到I/O Stream,而实际上,谁规定“流”就一定是“IO流”呢?在Java 8中,得益于Lambda所带 来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。
JDK8引入了集合类通过流的形式操作集合的函数
1.1 从集合获取流
根据Collection获取流 :
首先, java.util.Collection 接口中加入了default方法 stream 用来获取流,所以其所有实现类均可获取流。
/** Collection获取流 直接.stream */
private static Stream<String> getListStream(List<String> list){
return list.stream();
}
private static Stream<String> getSetStream(Set<String> set){
return set.stream();
}
private static Stream<String> getSetStream(Vector<String> vector){
return vector.stream();
}
Map获取流
private static void getSetStream(Map<String,String> map){
//获取键的流
Stream<String> keys = map.keySet().stream();
// 获取值得流
Stream<String> vals = map.values().stream();
// 获取entrySet流
Stream<Map.Entry<String,String>> entryStream = map.entrySet().stream();
}
数组获取流
private static void getSetStream(){
String[] array={"张无忌","张翠山","张三丰","张一元"};
Stream<String> stream = Stream.of(array);
stream.forEach(System.out::println);
}
映射:map
如果需要将流中的元素映射到另一个流中,可以使用 map 方法
/** stream流中的map方法的使用 */
private static void getMapStream(){
Stream<String> stream = Stream.of("12","5565","456");
Stream<Integer> result = stream.map(s->Integer.parseInt(s));
result.forEach(System.out::println);
}
统计个数:count
/** stream流中的map方法的使用 */
private static void getCountStream(){
Stream<String> stream = Stream.of("12","5565","456");
System.out.println("stream = " + stream.count());
}
取用前几个:limit
limit 方法可以对流进行截取,只取用前n个
/** stream流中的limit方法的使用 方法可以对流进行截取,只取用前n个*/
private static void getimStream(){
Stream<String> stream = Stream.of("张无忌","张三丰","周芷若");
Stream<String> result = stream.limit(2);
result.forEach(System.out::println);
}
skip方法
/** stream流中的skip方法的使用 跳过前几个元素,*/
private static void geskipStream(){
Stream<String> stream = Stream.of("张无忌","张三丰","周芷若");
Stream<String> result = stream.skip(2);
result.forEach(System.out::println);
}
流的合并
/** stream流中的concat方法的使用 如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat ,*/
private static void geConcatpStream(){
Stream<String> stream = Stream.of("张无忌","张三丰","周芷若");
Stream<String> stream2 = Stream.of("无忌张","三丰张","芷若周");
Stream<String> stream3 = Stream.concat(stream,stream2);
stream3.forEach(System.out::println);
}
综合练习
/** stream流综合练习*/
private static void demoStream(){
//第一支队伍
ArrayList<String> one=new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("石破天");
one.add("石中玉");
one.add("老子");
one.add("庄子");
one.add("洪七公");
//第二支队伍
ArrayList<String> two=new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("赵丽颖");
two.add("张三丰");
two.add("尼古拉斯赵四");
two.add("张天爱");
two.add("张二狗");
// 1. 一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。
Stream<String> one1 = one.stream().filter(s -> s.length() == 3);
one1.forEach(System.out::println);
// 2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中
Stream<String> one2 = one.stream().filter(s -> s.length() == 3).limit(3);
one2.forEach(System.out::println);
// 3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。
Stream<String> two1 = two.stream().filter(s -> s.startsWith("张"));
two1.forEach(System.out::println);
// 4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。
Stream<String> two2 = two.stream().filter(s -> s.startsWith("张")).skip(2);
two2.forEach(System.out::println);
// 5. 将两个队伍合并为一个队伍;存储到一个新集合中。
Stream<String> con = Stream.concat(one.stream(),two.stream());
con.forEach(System.out::println);
// 6. 根据姓名创建 Person 对象;存储到一个新集合中。
Stream<Person> con1 = Stream.concat(one.stream(),two.stream()).map(Person::new);
con1.forEach(System.out::println);
}
/** stream流综合练习*/
2 方法的引用
如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式——它们都 将被自动推导。而如果使用方法引用,也是同样可以根据上下文进行推导。
函数式接口是Lambda的基础,而方法引用是Lambda的孪生兄弟。双冒号 :: 为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。
public interface Greetable {
void greet();
}
public class Man{
public void doSomething() {
System.out.println("大家好,我是Emon!");
}
public static void method(Greetable g){
g.greet();
}
public static void main(String[] args) {
Man man = new Man();
method(man::doSomething);
}
}
2.1 通过类名称引用静态方法
public class Man{
public static void doSomething() {
System.out.println("大家好,我是Emon!");
}
public static void method(Greetable g){
g.greet();
}
public static void main(String[] args) {
Man man = new Man();
method(Man::doSomething);
}
}
2.2 通过super引用成员方法
public class Human {
public void sayHello()
{
System.out.println("Hello!");
}
}
}
public class Man extends Human {
@Override
public void sayHello() {
System.out.println("大家好,我是Man!");
}
public static void method(Greetable g){
g.greet();
}
public void show(){
// lambda方式的写法
method(() -> super.sayHello());
// 如果存在继承关系,当Lambda中需要出现super调用时,也可以使用方法引用进行替代。首先是函数式接口:
method(super::sayHello);
}
}
2.3 通过this引用成员方法
public class Human {
public void sayHello()
{
System.out.println("Hello!");
}
}
}
public class Man extends Human {
@Override
public void sayHello() {
System.out.println("大家好,我是Man!");
}
public static void method(Greetable g){
g.greet();
}
public void show(){
// lambda方式的写法
method(() -> this.sayHello());
// 如果存在继承关系,当Lambda中需要出现super调用时,也可以使用方法引用进行替代。首先是函数式接口:
method(this::sayHello);
}
}
2.4 类的构造器引用
由于构造器的名称与类名完全一样,并不固定。所以构造器引用使用 类名称::new 的格式表示。
public class Husband {
private String name;
public Person(String name) {
this.name = name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
public class Man{
public static void doSomething() {
System.out.println("大家好,我是Emon!");
}
public static void method(Greetable g){
g.greet();
}
public static void main(String[] args) {
method(Person::new);
}
}
2.5 数组构造器的使用
数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同。如果对应到Lambda的使用场景中时, 需要一个函数式接口
public interface ArrayBuilder {
int[] buildArray(int length);
}
public class Man {
public static int[] createArr(int len,ArrayBuilder arrayBuilder){
return arrayBuilder.buildArray(len);
}
public static void main(String[] args) {
int[] arr = createArr(10,int[]::new);
}
}