Java 8 流库学习笔记(一)

core Java学习笔记】Java SE8 流库 Stream Library

从迭代到流

如果要计算一个文本中有多少长单词(字母>12)。

  • 迭代式:

    words = getlist();//虚构方法,获得一个List<String>
    long count = 0;
    for(String w:words)
    {
    if(w.length()>12) count++;
    }
  • 流式:
    words = getlist();//虚构方法,获得一个List<String>
    long count = words.stream()
    .filter(w->w.length() > 12)
    .count();
  • 流式表达式相对于迭代式的好处:
    1. 易于阅读。
    2. 易于优化,例如将steam()方法换为parallelStream()方法就可以进行并行计算。
    3. 遵循"what, not how"原则,抽象层次更高。
  • 流的特征:
    1. 流不存储元素,元素可能存储在按需生成的匿名集合中。
    2. 流操作绝不会改变源数据。例如filter()方法不会移除数据,而是产生新的流。
    3. 流操作是lazy的,意味着直到流操作的结果被需要时才会进行运算。
  • 流操作的范式:
    1. 建立流。例如上例的stream()
    2. 应用intermediate operations使用原流去产生其他需要的流,可以进行多步。例如上例的filter()
    3. 应用terminal operation去产生结果。之后流将不可用。例如count()

建立流

  • 如果有Collection类,调用其stream()或其他流方法。
  • 如果有数组,使用Stream.of(Array array)方法。
  • 创建空流,调用Stream.empty()方法。
  • 创建无限长流,调用Stream.generate(Supplier supplier<T> s)方法。
    Stream<String> echos = Stream.generate(()->"Echo");
    //上方lambda表达式可写为如下完整表达式
    Stream<String> echos = Stream.generate(new Supplier<String>() {
            @Override
            public String get() {
                return "echo";
            }
        });
    Stream<Double> randoms = Stream.generate(Math::random);
    //产生随机数,双冒号是lambda表达式中的方法引用
  • 创建迭代的无限长流,使用Stream.iterate(T seed,UnaryOperator f)
    Stream<BigInteger> integers =
    Stream.iterate(BigInteger.ZERO,n->n.addd(BigInteger.ONE))
    //流的第一个元素为seed,后续元素为f(seed),f(f(seed))...
  • 字符串创建流,调用Pattern类中的spliteAsStream(CharSequence input)方法
    Pattern pattern = Pattern.compile(" ");
    Stream<String> s = pattern.splitAsStream("A B C");

filter,mapflatmap方法

最常用的三种intermediate operations

  • Stream<T> filter 方法:选择源流中符合一定条件的元素组成新流。

    List<String> wordList = ...;    //省略初始化
    Stream<String> longWords = wordList.Stream().filter(w -> w.length() > 12);
  • <R> Stream<R> map方法:对源流中所有元素执行同一操作后组成新流。
    List<String> words = ...;       //省略初始化
    Stream<String> lowercaseWords = words.stream().map(String::toLowerCase);
  • <R> Stream<R> flatmap方法:和map方法的效果大致相同,但对多个流组成的流操作会得到合并的一个流。即对Stream

    提取子流以及合并流

  • 调用Stream<T> limit(n)来提取前n个元素的子流。
    Stream<Double> randoms = Stream.generate(Math::random).limit(100);
  • 调用Stream<T> skip(n)来获得跳过前n个元素的子流
    Stream<String> words = Stream.of(contents.split("\\PL+")).skip(1);
  • 调用Stream<T> concate(Stream a,Stream b)来创建a,b流合并后的流,b在a后。

    其他流转换操作

  • Stream<T> distinct()获得相同顺序,但是只保留一个相同项的流。
    Stream<String> uniqueWords = Stream.of("a","a","b","c","a").distinct();
  • 使用Stream<T> sorted()对comparable排序,或使用Stream<T> sorted(Comparator<? super T> comparator)对普通对象元素排序。
    Stream<String> longestFirst = words
                            .stream()
                            .sorted(Comparator.comparing(String::length))
                            .reversed();
  • 使用Stream<T> peek(Consumer<? super T> action)在每次元素实际被访问时触发动作(action),利于debug。
    Object[] powers = Stream.iterate(1.0,p -> p * 2)
            .peek(e - > System.out.println("Peeking"+e))
            .limit(20).toArrays();

    简单的还原(reduction)操作

  • 还原操作是将流对象转换为非流对象的操作。
  • 还原操作是终止操作(terminal operations),操作之后流不可用。
  • count()计算流中元素个数。(上例有)
  • max(Comparator<? super T> comparator)min(Comparator<? super T> comparator)获得最大/最小元素。他们返回一个Optional<? super T>类。
    Optional<String> largest = words.max(String::compareToIgnoreCase);
    System.out.println("largest:" + largest.orElse(""));
  • findFirst()findAny()获得过滤器过滤到的第一个/所有元素。他们返回一个Optional<? super T>类。
    Optional<String> startsWithQ = words.filter(s -> s.startWith("Q")).findFirst();
  • anyMatch(Predicate<? super T> p),allMatch(Predicate<? super T> p),noneMatch(Predicate<? super T> p)返回匹配结果(boolean)。
    boolean aWordStartsWithQ = words.parallel().anyMatch(s -> s.startWith("Q"));

Optional

Optional类是流还原操作的常用返回值。Optional<T>持有(wrap)T类型对象或null的对象。这样的设计思路是为了安全,避免空引用。

简单地处理Optional对象中持有的对象。

  • T orElse(T other)如果该Optional对象非空,就返回持有的对象,否则返回other

    String result = optionalString.orElse("");
    //return wrapped string, or "" if null
  • T orElseGet(Supplier<? extends T> other)如果该Optional对象非空,就返回持有对象,否则返回other.get()
  • T orElseThrow(Supplier<? extends X> exceptionSupplier),如果该Optional对象非空,就返回持有的对象,否则抛出一个exceptionSupplier.get()异常。
  • ifPresent接受一个函数,如果option持有对象,则用该函数处理;否则无事发生。

    optionValue.ifPresent(v -> Process v);。该方法无返回值。

  • map方法和ifPresent类似,但是有一个Optional<T>的返回值,原Optional<T>对象不变。

正确地使用Optional

  • 随时警惕Optional对象可能不持有对象。这种特性可能造成NoSuchElementException错误的抛出。

    Optional<T> optionValue = ...;
    optionValue.get().someMethod();
    //not safe, cause get() may produce null
    Optional<T> optionValue = ...;
    if(optionValue.isPresent())
    optionValue.get().someMethod();
    //safe, cause isPresent() reports whether an Optional object has a value

    创建Optional类的对象

    创建Optional对象的主要方法是调用Optional类的静态工厂方法。

    static <T> Optional<T> of(T value)
    产生一个Optional对象,如果value是null,则抛出异常
    static <T> Optional<T> ofNullable(T value)
    产生一个Optional对象。
    static<T> Optional

    通过flatMap方法调用Optional<T>对象持有的T对象的方法。

//f() yields an Optional<T>
//T has a method g() yields an Optional<U>
Optional<U> result = s.f().flatMap(T::g)

收集流到集合中

  • 展示流

    stream.forEach(System.out::println);
  • 获得数组
    String[] result = stream.toArray(String::new);
    //toArray get Object[], pass it to constructor to get the right type.
  • 使用collect方法和Collectors类中众多的工厂方法来获得不同容器中的对象集合。
List<String> result = stream.collect(Collectors.toList());
Set<String> result = stream.collect(Collectors.toSet());
TreeSet<String> result = stream.collect(Collectors.toCollection(TreeSet::new));
//control which type of implementation of Collection

String result = stream.collect(Collectors.joining());
String result = stream.collect(Collectors.joining(", "));
//joing to one String

Iterator<T> iterator = stream.iterator();

IntSummaryStatistics summary = stream.collect(
    Collectors.summarizingInt(String::length));
double averageWordLength = summary.getAverage();
double maxWordLength = summary.getMax();
//summarizing(Int|Long|double) -> (Int|Long|Double)SummaryStatistisc

收集流到字典中

例如有一个Person类

Person{
    private int id;
    private String name;
    public getId(){
        return id;
    }
    public getName(){
        return name;
    }
    public Person(int id,String name){
        this.id = id;
        this.name = name;
    }
}
  • 一般情况
Map<Integer, String> keyToValue = stream.collect(
    Collectors.toMap(Person::getID,Person::getName));
    //(Function keyMapper, Function valueMapper)
  • 将对象整个作为键/值
Map<Integer, Person> idToPerson = stream.collect(
    Collectors.toMap(Person::getID,Function.identity()));

原文地址:https://www.cnblogs.com/QEStack/p/8480370.html

时间: 2024-10-28 15:49:22

Java 8 流库学习笔记(一)的相关文章

初探boost之timer库学习笔记

timer 用法 #include <boost/timer.hpp> #include <iostream> using namespace std; using namespace boost; int main() { timer t;//声明一个计时器对象,开始计时 cout<<"max:"<<t.elapsed_max()/3600<<"h"<<endl; //可度量的最大时间,以小时

java 集合基础1 学习笔记

集合特点: 1.用于存储对象的容器. 2.集合的长度是可变的. 3.集合中不可以存储基本数据类型值. Collection接口常见方法: 1.添加 boolean add(obj); boolean addAll(Collection coll); 2.删除 boolean remove(obj); boolean removeAll(Collection coll); void clear();//清空集合 3.判断 boolean contains(obj); boolean contain

Java快速教程--vamei 学习笔记(基础篇)

链接:http://www.cnblogs.com/vamei/archive/2013/03/31/2991531.html java快速教程第1课 从HelloWorld到面向对象 学习网址:http://www.cnblogs.com/vamei/archive/2013/03/14/2958654.html java快速教程第2课 方法与数据成员 学习网址:http://www.cnblogs.com/vamei/archive/2013/03/25/2964430.html java快

0806------Linux网络编程----------Echo 网络库 学习笔记

1.Echo网络库的编写 1.1 Echo网络库1.0 1.1.1 Echo网络库 1.0 框架分析 a)class InetAddress: 主要用来定义一个struct sockaddr_in 结构(用自定义端口号初始化),并提供获取这个结构体成员如IP.Port等的接口: b)class Socket : 主要用来把一个普通的 sockfd 变为 listenfd(这里用一个sockfd初始化对象),提供bind .listen.accept 等接口. c)class TcpConnect

Java快速教程--vamei 学习笔记(进阶篇)

感谢vamei,学习链接:http://www.cnblogs.com/vamei/archive/2013/03/31/2991531.html Java进阶01 String类 学习链接:http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html 字符串操作 ---------------------------------------------------------------------------------------

Java集合源码学习笔记(二)ArrayList分析

Java集合源码学习笔记(二)ArrayList分析 >>关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫"ArrayList",因为ArrayList内部是用一个数组存储元素值,相当于一个可变大小的数组,也就是动态数组. (1)继承和实现继承了AbstractList,实现了List:ArrayList是一个数组队列,提供了相关的添加.删除.修

JAVA的反射机制学习笔记(二)

上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了,自己的步伐完全被打乱了~不能继续被动下去,得重新找到自己的节奏. 4.获取类的Constructor 通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 Class<T>类提供了几个方法获取类的构造器. public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反

初探boost之progress_display库学习笔记

progress_display 用途 progress_display可以在控制台上显示程序的执行进度,如果程序执行很耗费时间,那么它能提供一个友好的用户界 面,不至于让用户在等待中失去耐心,甚至怀疑程序的运行是否出了问题. 用法示例 #include <boost/progress.hpp> #include <iostream> #include <vector> using namespace std; using namespace boost; int ma

初探boost之smart_ptr库学习笔记

概述 Boost.smart_ptr库提供了六种智能指针,除了shared_ptr 和 weak_ptr 以外还包括 scoped_ptr .scoped_array . shared_array .intrusive_ptr .他们的速度与原始指针相差无几,都是异常安全的,而且对于类型T也仅有一个要 求:类型T的析构函数不能抛出异常. 使用时包含头文件: #include<boost/smart_ptr.hpp> scoped_ptr 用法: scoped_ptr 的构造函数接受一个类型为T