天天看点

Java8流库

1 从迭代到流的操作

处理集合时,我们通常会用迭代遍历他的元素再进行某项运算,如求和、统计、获取元素等。当使用stream流时,我们不必扫描整个代码去查找或者过滤操作,方法名就可以直接告诉我们其代码完成什么操作。而且,循环需要非常详细地制定操作的顺序,而流却能够以其想要的任何方式来调用这些操作。
简单来说,流遵循了“想做什么而非怎么做”的原则。同时,仅将stream改为parallelStream就可以让流库以并行的方式进行过滤和技术。
           

1.1 流和集合的差异

1 流并不存储元素,这些元素可能存储在底层的集合中,或者是按需生成的。
2 流的操作不会修改其源数据。例如,filter方法不会将流中的数据移除,而是会生成一个新的流,且新的流中不包含过滤掉的元素。
           

1.2 简单示例

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamTest {
    public static void main(String[] args) {
        String str = "1,2,3,4,5";
        // 方式1 字符串转数组咋,再转成list,再转成流
//        List<String> arrStr = Arrays.asList(str.split(","));
//        List<Integer> arrInt = arrStr.stream().map(r -> Integer.parseInt(r)).collect(Collectors.toList());
        //方式2 数组直接转换成流的方法
        List<Integer> arrInt = Stream.of(str.split(",")).map(r -> Integer.parseInt(r)).collect(Collectors.toList());
        long count = arrInt.stream().count();
        System.out.println(count);
    }
}
           

2 流的创建

2.1 使用Collection接口的stream方法创建

Stream<String> stringStream1 = arrStr.stream();
           

2.2 如果是数组,则可以使用Stream.of()方法创建

直接传入一个数组对象  Stream<String> stringStream2 = Stream.of(str.split(","));
直接构建一个数组传入  Stream<String> stringStream3 = Stream.of("A","B","C");
           

2.3 可以选择数组的任意部分创建流

Stream<String> stringStream4 = Arrays.stream(str.split(","), 0, 2);
           

2.4 其他创建流的方式

1 创建一个元素为定值的流
	Stream<String> stringStream5 = Stream.of("s");
2 创建一个不包含任何元素的流
	Stream<String> stringStream6 = Stream.empty();
3 创建一个无限流,它的值可以通过反复调用函数来产生
	Stream<Double> stringStream7 = Stream.generate(Math::random);
。。。(挺多的)
           

3 filter、map和flatMap方法

3.1 filter

filter转换会产生一个新的流,它的元素与某种条件匹配,则会过滤。
使用方式:
	List<Integer> newIntList = arrInt.stream().filter(element -> element > 2).collect(Collectors.toList());
	element是指代流中的元素,可以任意命名,该filter()方法中,作为过滤的条件是element>2,即大于2的元素才会被添加到新的流中,最后被转换成list。
           

3.2 map

通常,我们想要按照某种方式来转换流中的值,此时,可以使用map方法并且传递执行该转换的函数,
使用方式:
	List<Integer> newIntList = arrStr.stream().map(element -> Integer.parseInt(element)).collect(Collectors.toList());
           

3.3 flatMap

假设有一个函数返回值是一个包含了众多值的流
           
public Stream<String> getStream(String s){
        return Stream.of(s.split("")); //将一个字符串拆成单个字母的流  ABCD -> ["A","B","C","D"]
    }
           
现在需要将其多个流合并成一个,即合并后的效果 ["A","B","C","D","E","F","G","H"],此时用map的话,就会变成 [["A","B","C","D"], ["E","F","G","H"]]
           
List<String> arrStr1 = Arrays.asList("ABCD","EFGH");
    Stream<Stream<String>> mapStream = arrStr1.stream().map(s -> getStream(s));
           
List<String> arrStr1 = Arrays.asList("ABCD","EFGH");
	Stream<String> flatMapStream = arrStr1.stream().flatMap(s -> getStream(s));
           

4 抽取子流和组合流

1 调用stream.limit(n)会返回一个新的流,它在n个元素之后结束(若n比流元素个数大,则该流结束时会结束)。
	  Stream<String> flatMapStream = arrStr1.stream().flatMap(s -> getStream(s)).limit(5);
2 调用stream.skip(n)会返回一个新的流,它会跳过n个元素之后开始执行。
	  Stream<String> flatMapStream = arrStr1.stream().flatMap(s -> getStream(s)).skip(2);
3 调用Stream的静态方法concat(streamA, streamB),会两个流组合并返回。
	 Stream<String> flatMapStream = Stream.concat(streamA, streamB);
           

5 其他的流转换

5.1 stream.distinct()

产生一个流,包含当前流中所有不同的元素,如下,使用distinct方法后,会把重复的"JJ"元素过滤只留一个。
 Stream<String> uniqueStr = Stream.of("JJ","JJ","JC").distinct();
           

5.2 stream.sorted()或stream.sorted(Comparator<? super T> comparator)

List<String> sortedStr = Stream.of("CCCC","BC","efg").sorted();	//该方法要求元素是实现了Comparable的类的实例
List<String> sortedStr = Stream.of("CCCC","BC","efg").sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
           

6 简单约简

约简是一种终结操作,它会将流约简为可以在程序中使用的非流值。如count方法,最终返回流中元素的数量。其他的还有min,max等方法。
           
package com.trip.demo;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamTest {
    public static void main(String[] args) {
        List<Integer> list = Stream.of(1,3,5,7,0).collect(Collectors.toList());
        long count = list.stream().count();
        System.out.println("元素个数:"+count);
        Optional<Integer> min = list.stream().min(Comparator.comparing(Integer::valueOf));
        System.out.println("最小值:"+min.get());
        Optional<Integer> max = list.stream().max(Comparator.comparing(Integer::valueOf));
        System.out.println("最大值:"+max.get());
    }
    
}
           
输出
Connected to the target VM, address: '127.0.0.1:31627', transport: 'socket'
元素个数:5
最小值:0
最大值:7
Disconnected from the target VM, address: '127.0.0.1:31627', transport: 'socket'

Process finished with exit code 0
           

7 Optional类型

7.1 获取Optional的值

package com.trip.demo;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Stream;

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

        //获取Optional值
        Optional<Integer> optional1 = Stream.of(1,3,5,7,0).min(Comparator.comparing(Integer::valueOf));
        Integer result1 = optional1.orElse(2);
        System.out.println("返回值:"+result1);
        //通过调用代码来计算默认值
        Integer result2 = optional1.orElseGet(()-> getValue());
        System.out.println("返回值:"+result2);
        //没有值时抛出异常
        try {
            Integer result3 = optional1.orElseThrow(Exception::new);
            System.out.println("返回值:"+result3);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static int getValue(){
        return 2;
    }
}

           

8 收集结果

package com.trip.demo;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamCollectorsTest {
    public static void main(String[] args) {
        //将流中的元素收集到另一个目标中
        //方式一 Collectors.toList()方法 收集成一个list
        List<Integer> list = Stream.of(1,3,5,7,0).collect(Collectors.toList());
        //方式二 Collectors.toSet()方法 收集成一个set
        Set<Integer> set = Stream.of(1,3,5,7,0).collect(Collectors.toSet());
        //方式三 Collectors.joining()方法 通过连接操作,收集成一个字符串
        String str1 = Stream.of("1","3","0").collect(Collectors.joining());
        //方式四 Collectors.joining(",")方法 可以再连接处增加连接符号等
        String str2 = Stream.of("1","3","0").collect(Collectors.joining(","));
        //方式五 先转换,再收集,Collectors.joining(",")方法 可以再连接处增加连接符号等
        String str3 = Stream.of(1,2,0).map(Object::toString).collect(Collectors.joining(","));
        //方式六 收集成map
        List<User> list = new ArrayList<>();
        list.add(new User("Java",1));
        list.add(new User("Python",2));
        Map<Integer, String> map = list.stream().collect(Collectors.toMap(User::getId, User::getName));
    }
}