Java8新特性笔记--波哥带你学JAVA--Stream Api


欢迎大家加入CSDN开发云
CSDN开发云

1.集合处理数据的弊端

当我在需要对集合中的元素进行操作的时候,除了必须的添加删除获取外,最典型的操作就是集合遍历

public class Demo01StreamApi {
    public static void main(String[] args) {
        // 定义一个集合
        List<String> list = Arrays.asList("张三","张三丰","成龙","周星驰");
        // 1.获取所有姓张的信息
        List<String> list1 = new ArrayList<>();
        for (String s : list) {
            if (s.startsWith("张")){
                list1.add(s);
            }
        }
        // 2.获取名称长度为3的用户
        List<String> list2 = new ArrayList<>();
        for (String s : list1) {
            if (s.length() == 3){
                list2.add(s);
            }
        }
        // 3.输出所有用户信息 张姓且三个字
        for (String s: list2) {
            System.out.println(s);
        }
    }
}

上面的代码针对于我们不同的需求总是一字字的循环循环,这是我们希望有更加高效的处理方式,
我们可以通过jdk8中提供的Stream Api来解决这个问题。

Stream更加优雅的解决方案:

public class Demo02StreamApi {
    public static void main(String[] args) {
        // 定义一个集合
        List<String> list = Arrays.asList("张三","张三丰","成龙","周星驰");
        // 1.获取所有姓张的信息
        // 2.获取名称长度为3的用户
        // 3.输出所有用户信息 张姓且三个字
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length() == 3)
                .forEach(s -> System.out.println(s));
        System.out.println("------------------------------------------------");
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length() == 3)
                .forEach(System.out::println);
    }
}

上面的StreamAPI代码的含义:获取流,过滤张,过滤字长,逐一打印。代码相比于上面的案例更加简洁直观。

2.Stream流的作用

Stream API能让我们快速完成许多复杂的操作,如筛选,切片,映射,查找,去重,统计,匹配和归约。

3.Stream流的获取方式

3.1 根据Collection获取

首先,java.util.Collection接口中加入了default方法stream,也就是说Collection接口下的所有实现都可以
通过stream方法来获取Stream流对象

public class Demo03StreamApi {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.stream();
        Set<String> set = new HashSet<>();
        set.stream();
        Vector vector = new Vector();
        vector.stream();
    }
}

但是Map接口没有实现Collection接口,这时该怎么办呢? 这是可以根据Map获取对应的key value的集合。

public class Demo04StreamApi {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        Stream<String> stream1 = map.keySet().stream();
        Stream<Object> stream2 = map.values().stream();
        Stream<Map.Entry<String, Object>> stream = map.entrySet().stream();
    }
}
3.2 通过Stream的of方法

在实际开发中我们不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所以Stream接口中
提供了静态方法of

public class Demo05StreamApi {
    public static void main(String[] args) {
        Stream<String> a1 = Stream.of("a1", "a2", "a3", "a4");
        String[] arr1 = {"aa","b","cc"};
        Stream<String> arr11 = Stream.of(arr1);
        Integer[] arr2 = {1,2,3,4};
        Stream<Integer> arr21 = Stream.of(arr2);
        arr21.forEach(System.out::println);
        // 注:基本数据类型的数组是不行的  会将数组数据看成一个整体
        int[] arr3 = {1,2,3,4};
        Stream.of(arr3).forEach(System.out::println);
    }
}

4.Stream常用方法介绍

终结方法:返回值类型不再是Sream类型的方法,不再支持链式调用,包括count和foreach。
非终结方法:返回值类型仍然是Stream类型的方法,支持链式调用。
Stream注意事项
1.Stream只能操作一次
2.Stream方法返回的是一个新的流
3.Stream不调用终结方法,中间的操作不会执行,必须以终结方法结束

4.1 forEach

foreach用来遍历流中的数据的

void forEach(Consumer<? super T> action);

该方法接受一个Consumer接口,会将每一个流元素交给函数处理

public class Demo07StreamApiForeach {
    public static void main(String[] args) {
       Stream.of("a1", "a2", "a3")
                .forEach(System.out::println);
    }
}
4.2 count

Stream流中的count方法用来统计其中的元素个数的

long count();

该方法返回一个long值,代表元素个数。

public class Demo08StreamApiCount {
    public static void main(String[] args) {
        long count = Stream.of("a1", "a2", "a3").count();
        System.out.println(count);
    }
}
4.3 filter

filter方法的作用是用来过滤数据的,返回符合条件的数据
可以通过filter方法讲一个流转换成另一个子集流

Stream<T> filter(Predicate<? super T> predicate);

该接口接受一个Predicate函数式接口参数作为筛选条件

public class Demo09StreamApiFilter {
    public static void main(String[] args) {
        Stream.of("a1", "a2", "a3","bb","cc","dd").filter(s -> s.contains("a"))
                .forEach(System.out::println);
    }
}
4.4 limit

limit方法可以对流进行截取处理,支取前n个数据

Stream<T> limit(long maxSize);

参数是一个long类型的数值,如果集合长度大于参数就进行截取,否则不操作:

public class Demo10StreamApiLimit {
  public static void main(String[] args) {
    Stream.of("a1", "a2", "a3", "bb", "cc", "aa", "dd").limit(5)
            .forEach(System.out::println);
  }
}
4.5 skip

如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流:

public class Demo11StreamApiSkip {
    public static void main(String[] args) {
        Stream.of("a1", "a2", "a3","bb","cc","aa","dd").skip(3)
                .forEach(System.out::println);
    }
} 
4.6 map

如果我们需要将流中的元素映射到另一个流中可以使用map方法;

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据

public class Demo12StreamApiMap {
    public static void main(String[] args) {
        Stream.of("1", "2", "3","4","5","6","7")
                //.map(s -> Integer.parseInt(s))
                .map(Integer::parseInt)
                .forEach(System.out::println);
    }
}
4.7 sorted

如果需要将数据排序,可以使用sorted方法:

Stream<T> sorted();

在使用的时候可以根据自然规则排序,也可以通过比较来指定对应的排序规则

public class Demo13StreamApiSorted {
  public static void main(String[] args) {
    Stream.of("1", "9", "3","4","22","6","7")
            .map(Integer::parseInt)
            //.sorted() //根据数据的自然顺序排序
            .sorted((o1,o2)->o2-o1) //根据比较指定排序规则
            //.sorted(Integer::compareTo)
            .forEach(System.out::println);
  }
}
4.8 distinct

如果要去掉重复的数据,可以使用distinct方法:

Stream<T> distinct();
public class Dmo14StreamApiDistinct {
  public static void main(String[] args) {
    Stream.of("1", "9", "3","4","3","6","7")
            .distinct() //去掉重复数据
            .forEach(System.out::println);
    System.out.println("---------------------------------");
    Stream.of(
                    new Person("张三",18,198),
                    new Person("李四",22,199),
                    new Person("张三",18,167)
            ).distinct()
            .forEach(System.out::println);
  }
}

Stream流中的 方法对于基本数据类型是可以直接去重的,但是对于自定义类型,我们是需要重写 hashCode和equals方法来移除重复元素

4.9 match

`如果需要判断数据是否匹配指定的条件,可以使用match相关的方法

boolean anyMatch(Predicate<? super T> predicate);// 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate);// 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate);// 元素是否都不满足条件

使用

public class Demo15StreamApiMatch {
    public static void main(String[] args) {
        boolean b = Stream.of("1", "9", "3", "4", "3", "6", "7")
                .map(Integer::parseInt)
                //.allMatch(s -> s > 0)
                //.anyMatch(s -> s > 4)
                .noneMatch(s-> s > 4);
        System.out.println(b);
    }
}

注意:match也是终结方法

4.10 find

如果我们需要找到某些元素,可以使用find方法来实现

Optional<T> findFirst();
Optional<T> findAny();

使用

public class Demo16StreamApiFind {
    public static void main(String[] args) {

        Optional<String> first = Stream.of("1", "9", "3", "4", "3", "6", "7").findFirst();
        System.out.println(first.get());

        Optional<String> any = Stream.of("1", "9", "3", "4", "3", "6", "7").findAny();
        System.out.println(any.get());
    }
}
4.11 max和min

如果我们想要获取最大值和最小值没那么可以使用max和min方法

Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);

使用

public class Demo17StreamApiMaxMin {
    public static void main(String[] args) {

        Optional<Integer> first = Stream.of("1", "9", "3", "4", "3", "6", "7")
                .map(Integer::parseInt)
                .max((o1,o2)->o1-o2);
        System.out.println(first.get());

        Optional<Integer> any = Stream.of("1", "9", "3", "4", "3", "6", "7")
                        .map(Integer::parseInt)
                        .min(((o1, o2) -> o1-o2));
        System.out.println(any.get());
    }
}
4.12 reduce

如果需要将所有数据归纳得到一个数据,使用reduce方法

T reduce(T identity, BinaryOperator<T> accumulator);

使用

public class Demo18StreamApiReduce {
    public static void main(String[] args) {
        Integer total = Stream.of(4, 5, 3, 9)
                // identity是默认值
                // 第一次的时候会将默认值赋给x
                // 之后每次会将上一次的操作结果赋值给x y就是每次从数据中获取的元素
                .reduce(0, (x, y) -> {
                    System.out.println("x="+x+",y="+y);
                    return x + y;
                });
        System.out.println(total);

        // 获取最大值
        Integer max = Stream.of(4, 5, 3, 9)
                .reduce(0, (x, y) -> {
                    return x > y ? x : y;
                });
        System.out.println(max);

        // 获取最小值
        Optional<Integer> reduce2 = Stream.of(4, 5, 3, 9)
                .reduce((x, y) -> {
                    return x < y ? x : y;
                });
        System.out.println(reduce2.get());
    }
}
4.13 map和reduce的组合

在实际开发中,我们经常会将map和reduce组合使用

public class Demo19StreamApiMapReduce {
    public static void main(String[] args) {
        //求年龄总和
        Integer sumAge = Stream.of(
                        new Person("张三", 18, 198),
                        new Person("李四", 22, 199),
                        new Person("张三", 18, 167),
                        new Person("赵六", 19, 176),
                        new Person("张三", 33, 180)
                ).map(Person::getAge)
                .reduce(0, Integer::sum);
        System.out.println(sumAge);
        // 求出年龄最大值
        Integer maxAge = Stream.of(
                        new Person("张三", 18, 198),
                        new Person("李四", 22, 199),
                        new Person("张三", 18, 167),
                        new Person("赵六", 19, 176),
                        new Person("张三", 33, 180)
                ).map(Person::getAge)
                .reduce(0, Math::max);
        System.out.println(maxAge);
        //统计 字符 a 出现的次数
        Integer count = Stream.of("a", "b", "c", "d", "a", "c", "a")
                .map(s -> "a".equals(s) ? 1 : 0)
                .reduce(0, Integer::sum);
        System.out.println(count);
    }
}
4.14 mapToInt

如果需要将Stream中的Integer类型转换成int类型,可以使用mapToInt方法来实现

public class Demo20StreamApiMapToInt {
    public static void main(String[] args) {
        // Integer占用的内存比int多很多,在stream流操作中会自动拆装箱操作
        Integer arr[] = {1,2,3,4,5};
        Stream.of(arr)
                .filter(integer -> integer > 0)
                .forEach(System.out::println);
        // 为了提高程序代码的效率, 我们可以现将流中Integer数据转换为int数据,然后操作
        Integer arr2[] = {1,2,3,4,5,7,9};
        Stream.of(arr2)
                .mapToInt(Integer::intValue)
                .filter(i -> i > 4)
                .forEach(System.out::println);
    }
}
4.15 concat

如果有两个流希望合并成为一个流,那么可以使用Stream接口的静态方法concat

public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);

        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }

使用:

public class Demo21StreamApiConcat {
    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("a", "b", "c");

        Stream<String> stream2 = Stream.of("x", "y", "z");
        // 通过concat方法将两个流合并成一个新的流
        Stream.concat(stream1,stream2)
                .forEach(System.out::println);
    }
}
4.16 综合案例
   public class Demo22StreamApiTest {
  /**
   * @methodName main
   * @description
   * 定义两个集合,然后再集合中存储多个用户名称,然后完成如下操作:
   *   1.第一个队伍只保留姓名长度为3的成员
   *   2.第一个队伍筛选后只要前三个
   *   3.第二个队伍只要姓张的成员
   *   4.第二个队伍筛选之后不要前两个人
   *   5.将两个队伍合并成一个队伍
   *   6.根据姓名创建Person对象
   *   7.打印整个队伍的Person信息
   * @author FredHe
   * @param args
   * @return
   * @since 2022/4/23 18:09
   */
  public static void main(String[] args) {

    List<String> list1 = Arrays.asList("迪丽热巴","宋远桥","苏星河","老子","庄子","孙子","洪七公");
    List<String> list2 = Arrays.asList("古力娜扎","张无忌","张三丰","赵丽颖","张二狗","张天爱","张三");

    // 1.第一个队伍只保留姓名长度为3的成员
    // 2.第一个队伍筛选后只要前三个
    Stream<String> stream1 = list1.stream().filter(s -> s.length() == 3).limit(3);

    // 3.第二个队伍只要姓张的成员
    // 4.第二个队伍筛选之后不要前两个人
    Stream<String> stream2 = list2.stream().filter(s -> s.startsWith("张")).skip(2);

    // 5.将两个队伍合并成一个队伍
    Stream<String> stream3 = Stream.concat(stream1, stream2);

    // 6.根据姓名创建Person对象
    // 7.打印整个队伍的Person信息
    stream3.map(Person::new).forEach(System.out::println);

  }
}

输出结果

Person(name=宋远桥, age=null, height=null)
Person(name=苏星河, age=null, height=null)
Person(name=洪七公, age=null, height=null)
Person(name=张二狗, age=null, height=null)
Person(name=张天爱, age=null, height=null)
Person(name=张三, age=null, height=null)

未完待续

本人代码笔记gitee地址:https://gitee.com/FredHeYuTong/learn-java8

欢迎大家加入CSDN开发云
CSDN开发云

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值