Stream API

2018-12-13  本文已影响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使用

上一篇下一篇

猜你喜欢

热点阅读