美文网首页
Stream API

Stream API

作者: 奉先 | 来源:发表于2018-12-13 23:54 被阅读3次

    Java 8中两大最重要的改动就是 Lambda表达式 和 Stream API。Stream是java 8中处理集合的关键抽象概念。集合讲的是数据,流讲的是计算
    Stream操作包含3个重要步骤,分别是创建Stream中间操作终止操作

    文章积累:https://www.cnblogs.com/lucky_dai/p/5485421.html

    1. 创建Stream流

    创建Stream包含三种常用方法:
    (1) java.util.Collection接口提供了2个方法stream()和parallelStream()可以创建Stream流。
    (2) Arrays的静态的方法stream()也可以获取数据流。
    (3) Stream.of() 方法可以通过显示值创建流。
    (4) 由函数创建流,无限流。可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。
    下面代码演示4种生成stream的方法:

    @Test
        public void test(){
            /**
            1. Collections(实现了Collections接口的类) 的 stream()方法
            和 parallelStream() 方法获取。
             */
            List<String> lis = new ArrayList<>();
            lis.add("Lucas");
            lis.add("Alice");
            lis.add("Jim");
            lis.add("Zeus");
            Stream<String> sl = lis.parallelStream();
            sl.forEach(System.out::println);
    
            /**
             * 2. 通过Arrays中的静态方法获取数组流
             */
            Employee[] emp = new Employee[]{
                    new Employee("Joe",28000,31),
                    new Employee("Lucy",5000,18),
                    new Employee("Robin",400,7),
                    new Employee("Cristina",40000,35),
                    new Employee("Fancy",18000,55),
                    new Employee("Lion",4000,26)
            };
            Stream<Employee> estr = Arrays.stream(emp);
            estr.forEach(System.out::println);
    
            /**
             * 3.通过Stream类的静态方法of获取数据流
             *
             * public static<T> Stream<T> of(T... values) {
             *         return Arrays.stream(values);
             *  }
             * T... 可变长参数,就是这个位置可以传入任意个该类型参数,简单来说就是个数组。
             *
             */
            Stream<Integer> estr1 = Stream.of(new Integer[]{5,6,7,2,1,9});
            estr1.forEach(System.out::println);
    
            /**
             * 4.由函数创建流,无限流。
             *   可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。
             *
             *  seed是种子,也就是初始值,后边UnaryOperator是一个Function函数式接口。
             *  public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
             *
             * public static<T> Stream<T> generate(Supplier<T> s)
             */
    
            Stream<Integer> si = Stream.iterate(0,x->x+2);
            si.limit(10).forEach(System.out::println);
    
            Stream si1 = Stream.generate(()->89);
            si1.limit(10).forEach(System.out::println);
        }
    

    2. Stream中间操作

    Stream中间可以经过多个类似“流水线”式的操作,除非执行了最后的终止操作,否则不会触发计算生成最后结果(这点和Spark和Flink的中间算子是类似的),也叫做惰性计算
    中间操作还可以分为几类:

    2.1. 筛选和切片:

    筛选和切片主要介绍4个方法,分别是: filter,distinct,limit,skip。
    四个方法都在接口中有定义,分别是:
    Stream<T> filter(Predicate<? super T> predicate);
    Stream<T> limit(long maxSize);
    Stream<T> distinct();
    Stream<T> skip(long n);
    前1,3个方法很好理解,主要介绍下第2,4个:
    skip: 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补。
    distinct:筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素

    @Test
        public void test02(){
            /**
             * 筛选和切片: filter,distinct,limit,skip;
             *
             * Stream<T> filter(Predicate<? super T> predicate);
             * Stream<T> limit(long maxSize);
             * Stream<T> distinct();
             * Stream<T> skip(long n);
             * skip: 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
             *
             * 内部迭代,迭代工作由Stream API完成。
             */
            //获取到流
            Stream<Employee> se = Arrays.stream(emp);
            se.filter((e)->e.getSalary()>10000)    //筛选大于10000工资的emp
                    .limit(3)
                    .distinct()
                    .forEach(System.out::println);
            System.out.println("---------------------------------------------");
            //获取到流
            Stream<Employee> se1 = Arrays.stream(emp);
            se1.skip(2)
                    .forEach(System.out::println);
        }
    

    2.2. 映射:

    映射主要包含map和flatMap。
    Map: 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    flatMap: 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

    public static Stream<Character> str2CharStream(String str){
            List<Character> li = new ArrayList<>();
    
            for(Character ch : str.toCharArray()){
                li.add(ch);
            }
            return li.stream();
        }
    
        @Test
        public void test03(){
            /**
             * 映射操作
             *     map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
             * <R> Stream<R> map(Function<? super T, ? extends R> mapper);
             * <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
             *
             * flatMap将每一个字符串拆分成一个Character Stream后,再将所有的字符,串成一个大的字符Stream。
             */
    
            Integer[] sers = new Integer[]{9,8,3,2,1,34,76};
            Stream<Integer> st1 = Arrays.stream(sers);
            st1.map(x -> x+20)
                    .map(x -> x+".3")
                    .map(x -> Double.valueOf(x))
                    .forEach(System.out::println);
    
            String[] sers1 = new String[]{"Alice","Bob","Christina","Rose","Peak"};
            Stream<String> st2 = Arrays.stream(sers1);
            Stream<Character> ssc = st2.flatMap(StreamAPI::str2CharStream);
            ssc.forEach(System.out::println);
        }
    

    3. Stream API的练习:

    针对上边的API内容,设计了下边的实验方法。题目的说明在代码中有显示。
    Trader.java

    public class Trader {
    
        private String name;
        private String city;
    
        public Trader() {
        }
    
        public Trader(String name, String city) {
            this.name = name;
            this.city = city;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        @Override
        public String toString() {
            return "Trader [name=" + name + ", city=" + city + "]";
        }
    }
    

    Transaction.java

    public class Transaction {
    
        private Trader trader;
        private int year;
        private int value;
    
        public Transaction() {
        }
    
        public Transaction(Trader trader, int year, int value) {
            this.trader = trader;
            this.year = year;
            this.value = value;
        }
    
        public Trader getTrader() {
            return trader;
        }
    
        public void setTrader(Trader trader) {
            this.trader = trader;
        }
    
        public int getYear() {
            return year;
        }
    
        public void setYear(int year) {
            this.year = year;
        }
    
        public int getValue() {
            return value;
        }
    
        public void setValue(int value) {
            this.value = value;
        }
    
        @Override
        public String toString() {
            return "Transaction [trader=" + trader + ", year=" + year + ", value="
                    + value + "]";
        }
    
    }
    

    StreamTest.java

    public class StreamTest {
    
        /**
         *  1. 给定一个数字列表,返回每个数字的平方组成的列表,例如输入 1,3,7,8  返回 1,9,49,64
         * @param input_list   一个数字列表
         * @return             数字的平方组成的列表
         */
        public List<Integer> squareCal(List<Integer> input_list){
           Stream<Integer> st_in = input_list.stream();
    
           List<Integer> out_list =
                   st_in.map(x -> x*x)
                   .collect(Collectors.toList());
           return out_list;
        }
    
        /**
         *  2.使用map 和reduce方法 数一数流中有多少个Employee
         * @param emp   Employee对象列表
         * @return
         */
        public int CountEmp(List<Employee> emp){
            return emp.stream()
                    .map(e -> 1)
                    .reduce(0,(x,y ) -> x+y);
        }
    
        /**
         * 3. 使用基础类Trader, Transaction ,并使用Stream完成如下一些需求:
         * 1) 找出2011年发生的所有交易,并按照交易额排序(从低到高)
         * 2) 交易员都在哪些不同的城市工作过。
         * 3) 查找所有来自剑桥的交易员,并按照名字排序。
         * 4)返回所有交易员的姓名字符串,按字母排序。
         * 5) 打印生活在剑桥的交易员的交易额
         * 6)所有的交易中,最高的交易额是多少
         * 7)找到交易额最小的交易
         * 8)有没有在米兰工作的交易员。
         * */
    
        public void transactionTest(){
    
            //初始化基础测试数据
            Trader raoul = new Trader("Raoul", "Cambridge");
            Trader mario = new Trader("Mario", "Milan");
            Trader alan = new Trader("Alan", "Cambridge");
            Trader brian = new Trader("Brian", "Cambridge");
    
           List<Transaction> transactions =  Arrays.asList(
                    new Transaction(brian, 2011, 300),
                    new Transaction(raoul, 2012, 1000),
                    new Transaction(raoul, 2011, 400),
                    new Transaction(mario, 2012, 710),
                    new Transaction(mario, 2012, 700),
                    new Transaction(alan, 2012, 950)
            );
    
           System.out.println(" --------------------找出2011年发生的所有交易,并按照交易额排序(从低到高)--------------------");
            transactions.stream()
                    .filter(t -> t.getYear() == 2011)
                    .sorted((x,y) ->Integer.compare(x.getValue(),y.getValue()))
                    .forEach(System.out::println);
    
            System.out.println(" --------------------交易员都在哪些不同的城市工作过--------------------");
            transactions.stream()
                    .map(x ->x.getTrader().getCity())
                    .distinct()
                    .forEach(System.out::println);
    
            System.out.println(" --------------------查找所有来自剑桥的交易员,并按照名字排序--------------------");
            transactions.stream()
                    .filter(x ->x.getTrader().getCity().equals("Cambridge"))
                    .map(x -> x.getTrader() )
                    .sorted((x,y) -> x.getName().compareTo(y.getName()))
                    .distinct()
                    .forEach(System.out::println);
    
            System.out.println(" --------------------返回所有交易员的姓名字符串,按字母排序--------------------");
            transactions.stream()
                    .map(x -> x.getTrader().getName())
                    .sorted((x,y) -> x.compareTo(y))
                    .forEach(System.out::println);
    
            System.out.println(" --------------------打印生活在剑桥的交易员的交易额--------------------");
            transactions.stream()
                    .filter(x -> x.getTrader().getCity().equals("Cambridge"))
                    .map(x -> x.getValue())
                    .forEach(System.out::println);
    
            System.out.println(" --------------------所有的交易中,最高的交易额是多少--------------------");
            Optional<Integer> max_value =  transactions.stream()
                    .max((x,y) -> Integer.compare(x.getValue(),y.getValue()))
                    .map(x -> x.getValue());
            System.out.println(max_value.get());
    
    
            System.out.println(" --------------------找到交易额最小的交易--------------------");
            Optional<Transaction> min_trans = transactions.stream()
                    .min((x,y) -> Integer.compare(x.getValue(),y.getValue()))
                    ;
            System.out.println(min_trans.get());
    
            System.out.println(" --------------------有没有在米兰工作的交易员--------------------");
            boolean Milan_exi = transactions.stream()
                    .map(x -> x.getTrader())
                    .anyMatch(x -> x.getCity().equals("Milan"));
            System.out.println(Milan_exi);
    
        }
    
        public static void main(String[] args) {
            StreamTest st_ob = new StreamTest();
    
            // 问题1 测试
            List<Integer> list = Arrays.asList(4,8,2,199,5,37);
            System.out.println(Arrays.toString(st_ob.squareCal(list).toArray()));
    
            //问题2 测试
            List<Employee> emp_list = Arrays.asList(
                    new Employee("Joe",28000,31),
                    new Employee("Denny",5000,36),
                    new Employee("Lucy",5000,18),
                    new Employee("Robin",400,7),
                    new Employee("Cristina",40000,35),
                    new Employee("Fancy",18000,55),
                    new Employee("Lion",4000,26)
            );
            System.out.println(st_ob.CountEmp(emp_list));
    
            //问题3 测试:qa
            st_ob.transactionTest();
        }
    }
    

    4. Fork&Join框架

    ======== 返回目录 ========
    《《《 上一篇 Java 8 Lamda表达式
    》》》 下一篇 Git 和 intellij idea使用

    相关文章

      网友评论

          本文标题:Stream API

          本文链接:https://www.haomeiwen.com/subject/dgwihqtx.html