Java SE-Stream流

流概述
获取流
流模型的操作方法
方法引用

流式思想概述
  • 区别于传统的IO流,这里的流而是一种流水线思想
流式思想示意图
  • 这里的filter、map、skip都只是对函数模型进行操作,并没有真正对集合元素处理,只有当最终方法count执行时,整个模型才会按照指定策略执行,这得益于lambda的延迟执行特性
  • Java中stream流并不会存储元素,而是按需计算

在这里插入图片描述

获取流
  • 1、所有的Collection集合都可以通过stream默认方法获取流
  • 2、Stream接口静态方法of可以获取数组对应的流
  • Stream流是jdk1.8之后出现的
  • 不关注怎么做,而关注做什么
import java.util.*;
import java.util.stream.Stream;

/**
 *  java.util.stream.Stream<T>是Java8新加入的常用接口(这不是一个函数式接口)
 *     获取流的常用方式:
 *       1、所有的Collection集合都可以通过stream默认方法获取流
 *          default Stream<E> stream()
 *       2、Stream接口静态方法of可以获取数组对应的流
 *          static <T> Stream<T> of(T...value)
 *          参数是一个可变参数,这这我们可以传递一个数组
 */
public class Demo02GetStream {
    public static void main(String[] args) {
        //把集合转换为Stream流
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> stream1 = set.stream();

        Map<String, String> map = new HashMap<>();
        //获取键存储到set集合
        Set<String> set1 = map.keySet();
        Stream<String> stream2 = set1.stream();

        //获取值
        Collection<String> collection = map.values();
        Stream<String> stream3 = collection.stream();

        //获取键值对映射到entrySet集合
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        Stream<Map.Entry<String, String>> stream4 = entrySet.stream();

        //把数组转换为stream流
        Stream<Integer> stream5 = Stream.of(1,2,3,4);
        Integer[] arr = {1,2,34};
        Stream<Integer> stream6 = Stream.of(arr);
    }
}

流模型的操作方法
延迟方法
  • 返回值类型仍是Stream接口的自身类型方法,因此支持链式调用
终结方法
  • 返回值类型不再是Stream接口的自身类型方法,因此不再 支持链式调用
forEach方法
  • 该方法接收一个Consumer接口类型函数
import java.util.stream.Stream;

/**
 *   Stream流中常用方法foreach
 *   该方法接收一个Consumer接口类型函数
 *    简单记:
 *       forEach方法,用来遍历流中的数据
 *       是一个终结方法,用来之后就不能遍历其它方法
 */
public class Demo01ForEach {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("小明", "小马", "xiaohua");

        //遍历
        stream.forEach(name-> System.out.println(name));
    }
}

filter方法
  • Stream流中filter方法,对流中数据进行过滤
  • filter方法参数Predicate是一个函数式接口
import java.util.stream.Stream;

/**
 *   Stream流中filter方法,对流中数据进行过滤
 *   filter方法参数Predicate是一个函数式接口
 */
public class Demo01Filter {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("小明", "小马", "xiaohua");
        //过滤
        Stream<String> stream1 = stream.filter((name)->name.startsWith("小"));
        //遍历
        stream1.forEach(name-> System.out.println(name));

        /**
         *   注意事项:
         *      Stream流属于管道流,只能使用一次自动关闭
         *      第一个Stream流调用完毕,数据就会转到下一个Stream上
         *      这时第一个Stream流使用完毕,就会关闭
         *      所以第一个Stream流就不能再调用方法
         */
    }
}

映射map方法
  • 如果要将流中的元素映射到另一个流中,可以使用map方法
  • 该接口选择一个Function 函数式接口作为参数
import java.util.stream.Stream;

/**
 * r 如果要将流中的元素映射到另一个流中,可以使用map方法
 *   该接口选择一个Function 函数式接口作为参数
 */
public class Demo01Map {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("1", "2", "3", "4");
        //使用映射,把字符串类型转换为整数
        Stream<Integer> map = stream.map(value->Integer.parseInt(value));

        //遍历
        map.forEach(i-> System.out.println(i));
    }
}

统计个数:count
  • Stream 流中count方法,用于统计Stream流中元素的个数
  • count方法是一个终结方法,返回值是一个long类型的整数
  • 不能再调用stream流中其它方法
import java.time.temporal.JulianFields;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/**
 *  Stream 流中count方法,用于统计Stream流中元素的个数
 *  long count()
 *  count方法是一个终结方法,返回值是一个long类型的整数
 *  不能再调用stream流中其它方法
 */
public class Demo01Count {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        Stream<Integer> stream = list.stream();
        long count = stream.count();
        System.out.println(count);
    }
}

取前几个limit
  • Stream流中limit方法,用于截取流中元素
  • limit方法可以可以对流进行截取,只能取前n个
  • Stream limit(long maxsize) 如果集合当前长度大于参数则进行截取,否则不做处理
import java.util.stream.Stream;

/**
 *   Stream流中limit方法,用于截取流中元素
 *     limit方法可以可以对六进行截取,只能取前n个
 *     Stream<T>  limit(long maxsize) 如果集合当前长度大于参数则进行截取,否则不做处理
 *     limit方法是一个延迟方法,只是对流中的元素进行截取,所以可以继续调用Stream流中的其它方法
 */
public class Demo01Limit {
    public static void main(String[] args) {
        String[] arr = {"小狗", "小猫", "大王"};
        Stream<String> stream = Stream.of(arr);

        //使用limit方法对流进行截取
        Stream<String> stream1 = stream.limit(2);

        //遍历
        stream1.forEach(name-> System.out.println(name));
    }
}

跳过前几个skip
  • Stream流中skip方法用于跳过元素
  • 如果希望跳过前几个元素,可以使用skip方法获取一个截取之后的新流
  • 如果当前长度大于参数n,则跳过前n个,否则会得到一个长度为0的新流
import java.util.stream.Stream;

/**
 *   Stream流中skip方法用于跳过元素
 *   如果希望跳过前几个元素,可以使用skip方法获取一个截取之后的新流
 *   Stream<T> skip(long n)
 *      如果当前长度大于参数n,则跳过前n个,否则会得到一个长度为0的新流
 */
public class Demo01Skip {
    public static void main(String[] args) {
        String[] arr = {"小狗", "小猫", "大王"};
        Stream<String> stream = Stream.of(arr);

        //使用skip跳过前1个元素
        Stream<String> stream1 = stream.skip(1);

        //遍历
        stream1.forEach(name-> System.out.println(name));
    }
}

concat连接多个流
  • Stream流中concat方法把多个流合并乘一个流
/**
 *   Stream流中concat方法把俩个流合并乘一个流
 *
 */
public class Demo01Concat {
    public static void main(String[] args) {
        String[] arr = {"小狗", "小猫", "大王"};
        Stream<String> stream = Stream.of(arr);

        String[] arr2 = {"马龙", "张继科", "樊振东"};
        Stream<String> stream1 = Stream.of(arr2);
        //把俩个流合并成一个流
        Stream<String> stream2 = Stream.concat(stream, stream1);

        //遍历
        stream1.forEach(name-> System.out.println(name));
    }
}

方法引用
  • :: 被称为方法引用运算符,而它所在的表达式被称为方法引用
/**
 *   定义一个打印的函数式接口
 */
@FunctionalInterface
public interface Printable {
    void print(String s);
}

/**
 *
 */
public class Demo01Printable {
    /**
     *  定义一个方法,传递Printable接口,对字符串打印
     */
    public static void printString(Printable p) {
        p.print("hello");
    }

    public static void main(String[] args) {
        //调用printable方法,传递lambda表达式
        printString(s-> System.out.println(s));

        /**
         *   分析:
         *      lambda表达式目的:打印参数传递的字符串
         *      把参数s传递给了System.out对象,调用out方法中的println对字符串输出
         *      注意:
         *         System.out 对象是已经存在的
         *         println 方法也是存在的
         *         所以可以直接使用System.out方法直接引用println方法
         *         :: 被称为方法引用运算符,而它所在的表达式被称为方法引用
         *         如果lambda要表达的函数方案已经存在于某个方法的实现中,那么可以通过::来引用该方法作为lambda表达式的替代者
         *      区别:
         *         第一种lambda语义:拿到参数之后经过lambda表达式之手,进而传递给System.out.println方法去处理
         *         第二种语义,直接让System.out的println方法去替代lambda表达式
         *         注意:lambda中传递的参数一定是方法引用中那个方法可以接受的类型,否则会抛出异常
         */
        printString(System.out::println);
    }
}


通过对象引用成员方法
  • 通过对象来引用成员方法前提是对象名已经存在,成员方法已经存在
/**
 *   定义一个打印的函数式接口
 */
@FunctionalInterface
public interface Printable {
    void print(String s);
}

public class Demo01MethodObject {
    //定义一个成员方法,传递字符串并且按照大写输出
    public void printUpperCaseString(String s) {
        System.out.println(s.toUpperCase());
    }
}

import com.thread.demo12waitandnotify.Demo;

/**
 *   通过对象来引用成员方法
 *   前提是对象名已经存在,成员方法已经存在
 */
public class Demo01ObjectMethodReference {
    public static void printString(Printable p) {
        p.print("hello");
    }

    public static void main(String[] args) {
        //调用上述方法,传递一个lambda表达式
        printString((s)-> {
            //创建一个MethodObject对象
            Demo01MethodObject obj = new Demo01MethodObject();
            //调用成员方法,按照大写输出
            obj.printUpperCaseString(s);
        });

        /**
         *   方法优化
         *      对象存在
         *      成员方法存在
         *      所以可以通过对象名引用成员方法
         */
        Demo01MethodObject obj = new Demo01MethodObject();
        printString(obj::printUpperCaseString);
    }
}


通过类名引用静态成员方法
  • 通过类名引用静态成员方法前提类已经存在,静态成员方法也已经存在
public interface Calcable {
    /**
     *  定义一个抽象方法,传递一个整数,返回绝对值
     */
    int calAbs(int num);
}

/**
 *   通过类名引用静态成员方法
 *   类已经存在,静态成员方法也已经存在
 *   可以通过类名引用静态成员方法
 */
public class Demo01StaticMethodReference {
    //定义一个方法,传递一个参数,另一个参数类型为接口
    public static int method(int num, Calcable c) {
        return c.calAbs(num);
    }

    public static void main(String[] args) {
        //调用方法计算绝对值
        int num = method(-10, (n)-> {
            return Math.abs(n);
        });

        System.out.println(num);

        /**
         *   使用方法优化lambda表达式
         *     Math类是存在的
         *     abs计算绝对值得警惕方法也是存在的
         *     所以可以通过类名调用成员方法
         */
        int num1 = method(-10, Math::abs);
        System.out.println(num1);
    }
}

通过super调用父类的成员方法
  • 使用super引用父类的成员方法前提super已经存在父类的成员方法sayHello已经存在
public interface Greetable {
    //定义一个见面的方法
    void greet();
}

/**
 *   定义父类
 */
public class Human {
    public void sayHello() {
        System.out.println("hello 我是Human");
    }
}

/**
 * 定义子类
 */
public class Man extends Human {
    //子类重写父类方法

    @Override
    public void sayHello() {
        System.out.println("hello 我是man");
    }

    //定义一个方法传递Greetable接口
    public void method(Greetable g) {
        g.greet();
    }

    public void show() {
        //调用method方法
        method(()-> {
            //创建父类对象
            Human h = new Human();
            //调用父类方法
            h.sayHello();
        });

        //因为有子父类,所以存在一个关键字,代表父类,可以直接使用super调用父类的成员方法
        method(()-> {
            super.sayHello();
        });

        /**
         *   使用super引用父类的成员方法
         *   super已经存在
         *   父类的成员方法sayHello已经存在
         *   所以可以直接使用super引用父类的成员方法
         */
        method(super::sayHello);
    }

    public static void main(String[] args) {
        new Man().show();
    }
}


引用本类的成员方法
  • 引用本类的成员方法前提this存在本类成员方法也存在
/**
 *   定义一个富有的函数式接口
 */
public interface Richable {
    //定义一个想买什么就买什么的方法
    void buy();
}

/**
 *   通过this引用本类的成员方法
 */
public class Husband {
    //定义一个买房子的方法
    public void buyHouse() {
        System.out.println("北京二环内每一套四合院");
    }

    //定义一个结婚方法,传递Richable接口
    public void marry(Richable r) {
        r.buy();
    }

    //定义一个非常高兴的方法
    public void soHappy() {
        //调用结婚的方法,参数传递一个lambda表达式
        marry(()-> {
            //调用本类的成员方法
            this.buyHouse();
        });

        /**
         *   使用方法引用优化lambda表达式
         *   this存在
         *   本类成员方法也存在
         *   所以可以通过this引用本类的成员方法
         */
        marry(this::soHappy);
    }

    public static void main(String[] args) {
        new Husband().soHappy();
    }
数组构造器的引用
  • 数组构造器的引用前提已知创建的是int[]数组,数组的长度已知
/**
 *  定义一个创建数组的函数式接口
 */
public interface ArrayBuilder {
    //定义一个创建int类型数组的方法
    int[] builderArray(int length);
}

/**
 *   数组的构造器引用
 */
public class Demo {
    /**
     *   定义一个方法
     *   方法参数传递创建数组的长度和Arraybuilder接口
     */
    public static int[] createArray(int length, ArrayBuilder ab) {
        return ab.builderArray(length);
    }

    public static void main(String[] args) {
        //调用上述方法创建数组
        int[] arr = createArray(10, (len)-> new int[len]);
        System.out.println(arr.length);
        /**
         *  使用lambda表达式优化
         *  已知创建的是int[]数组
         *  数组的长度已知
         *  可以使用方法引用来创建数组
         */
        int[] arr2 = createArray(20,int[]::new);
        System.out.println(arr2.length);
    }
}

类的构造器引用
  • 类的构造器引用前提构造方法已知,创建对象已知
/**
 *   定义一个创建Person对象的函数式接口
 */
@FunctionalInterface
public interface PersonBuilder {
    //定义一个方法,根据传递的姓名返回对象
    Person builderPerson(String name);
}

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

/**
 *   类的构造器引用
 */
public class Demo {
    //定义一个方法,根据传递字符串返回对象
    public static void printName(String name, PersonBuilder pb) {
        Person person = pb.builderPerson(name);
        System.out.println(person);
    }

    public static void main(String[] args) {
        //调用构造对象的安方法
        printName("张继科", name -> new Person(name));

        /**
         *   使用优化的lambda表达式
         *    构造方法new Person(String name) 已知
         *    创建对象已知
         *    可以使用其创建对象
         */
        printName("马龙", Person::new);  //使用Person类的带参构造方法,通过传递姓名创建对象
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值