Bootstrap

Stream流和Optional

一、Stream

1.获取Stream流

  1. 所有的 Collection 集合都可以通过 stream 默认方法获取流(顺序流);
  2. 所有的 Collection 集合都可以通过parallelStream获取并行流
  3. Stream 接口的静态方法 of 可以获取数组对应的流。
  4. Arrays的静态方法stream也可以获取流

根据Collection获取流
Collection接口中有一个stream()方法,可以获取流 , default Stream stream():获取一个Stream流

通过List集合获取:
通过Set集合获取
  public static void main(String[] args) {
    
	List<String> list = new ArrayList<>();
	Stream<String> stream1 = list.stream();
    
	Set<String> set = new HashSet<>();
	Stream<String> stream2 = set.stream();
    
	Vector<String> vector = new Vector<>();
	// ...
	}    

根据Map获取流

使用所有键的集合来获取流
使用所有值的集合来获取流
public static void main(String[] args) {
    
	Map<String, String> map = new HashMap<>();
	
	Stream<String> keyStream = map.keySet().stream();
	Stream<String> valueStream = map.values().stream();
	Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
}

根据数组获取流

Stream接口,表示流,泛型T是用来限制流中元素的类型
Stream流中有一个static Stream of(T… values)
通过数组获取:
通过直接给多个数据的方式
    public static void main(String[] args) {
    //使用 Stream.of
	String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
	Stream<String> stream = Stream.of(array);
    
    //使用Arrays的静态方法
    Arrays.stream(array)
	}

Stream中方法可以分为两种:

  • 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。)
  • 终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder
    那样的链式调用。本小节中,终结方法包括 count 和 forEach 方法。

1.forEach(终结方法)
遍历方法:

public static void main(String[] args) {
	Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");
	stream.forEach(name‐> System.out.println(name));
}

2.过滤:filter

public static void main(String[] args) {

        //创建一个流
        Stream<String> stream = Stream.of("张三丰", "刘德华", "张国荣", "彭于晏", "纳什", "吴彦祖", "吴绮蓉");

        //对流中元素过滤,只要姓张的人
        Stream<String> stream2 = stream.filter(name -> {
            return name.startsWith("张");
        });
        
        //遍历过滤后的流
        stream2.forEach(name -> System.out.println(name));
    }

3.映射(转换):map
将流中的元素映射到另一个流中

	@Test
    public void test(){

        //创建一个流,里面是字符串类型的整数
        Stream<String> stream1 = Stream.of("2", "32", "2", "33", "2");
        
        //把stream1流中的整数全部转成int类型
        Stream<Integer> stream2 = stream1.map((String s) -> {
            return Integer.parseInt(s);
        });

        //遍历
        stream2.forEach((i)-> System.out.println(i));

    }

4.统计个数:count(终结方法)
返回一个long值代表元素个数

public class Demo09StreamCount {
    
	public static void main(String[] args) {
        
		Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        
        //筛选姓张的
		Stream<String> result = original.filter(s ‐> s.startsWith("张"));
        
        //输出个数
		System.out.println(result.count()); // 2
	}
}

5.取用前几个(截取):limit
对流进行截取,只取用前n个。参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作

public class Demo10StreamLimit {
    
	public static void main(String[] args) {
		Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        //截取前两个
		Stream<String> result = original.limit(2);
        
		System.out.println(result.count()); // 2
	}
}

6.跳过前几个元素:skip
流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流.

public class Demo11StreamSkip {
    
	public static void main(String[] args) {
        
		Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
        //跳过前两个,返回一个新的流
		Stream<String> result = original.skip(2);
		System.out.println(result.count()); // 1
	}
}

7.组合(合并流):concat

public class Demo12StreamConcat {
    
	public static void main(String[] args) {
		Stream<String> streamA = Stream.of("张无忌");
		Stream<String> streamB = Stream.of("张翠山");
        //合并成一个新的流
		Stream<String> result = Stream.concat(streamA, streamB);
	}
}

8.映射(打开后再转换):flatMap
内部传入一个Function函数式接口,跟map的区别就是这个会把流中的元素打开,再组合成一个新的流。

// map和flatMap的练习
public class StreamDemo {

    @Test
    public void test(){
        List<String> list = Arrays.asList("aa","bb","cc","dd");

        // 练习1 (map) 输出的全是大写
        list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
        System.out.println("----------");

        // 练习2(map)流里还有流,需要两个遍历才行看到里面内容
        Stream<Stream<Character>> streamStream = list.stream().map(StreamDemo::fromStringToStream);
        streamStream.forEach(s -> {
            s.forEach(System.out::println);
        });

        System.out.println("---------");
        // 练习3(flatMap)流里还有流,使用flatMap可以直接把里面的流打开,一次遍历就可以了
        Stream<Character> characterStream = list.stream().flatMap(StreamDemo::fromStringToStream);
        characterStream.forEach(System.out::println);
        
    }

    /**
     *  将字符串中的多个字符构成的集合转换为对应的stream
     * @param str
     * @return
     */
    public static Stream<Character> fromStringToStream(String str){
        ArrayList<Character> list = new ArrayList();
        // 将字符串转成字符数组,并遍历加入list集合
        for(Character c : str.toCharArray()){
            list.add(c);
        }
        // 返回list集合的stream流
        return list.stream();
    }
}

10.排序

	 /**
     * 排序的练习
     */
    @Test
    public void test2(){

        List<Integer> integers = List.of(124, 2, 15, 12, 51, -5, 5);
        // 按照自然排序
        integers.stream().sorted().forEach(System.out::println);

        System.out.println("---------");

        List<Integer> integers2 = List.of(124, 2, 15, 12, 51, -5, 5);
        // 定制排序(大到小),需要传入Comparator接口(如果流中的是引用类型,只能用定制排序)
        // 简写:integers2.stream().sorted((e1,e2) -> e2-e1).forEach(System.out::println);
        integers2.stream().sorted((e1,e2) -> {
            return e2-e1;
        }).forEach(System.out::println);
    }

11…检测匹配(终结方法):
返回一个Boolean值

是否全部匹配:allMatch

是否至少匹配一个:anyMatch

是否没有匹配的:noneMatch

	 /**
     * 匹配的练习
     */
    @Test
    public void test3(){
        List<Integer> integers = List.of(124, 2, 15, 12, 51, -5, 5);
        // 判断是否全部大于5
        boolean b = integers.stream().allMatch(i -> i > 5);
        // 结束输出false
        System.out.println(b);

        System.out.println("-------");

        List<Integer> integers2 = List.of(124, 2, 15, 12, 51, -5, 5);
        // 检测是否匹配至少一个元素
        boolean b1 = integers2.stream().anyMatch(i -> i > 5);
        // 输出true
        System.out.println(b1);

        System.out.println("-------");

        List<Integer> integers3 = List.of(124, 2, 15, 12, 51, -5, 5);
        // 检查是否没有匹配的元素
        boolean b2 = integers3.stream().noneMatch(i -> i > 1000);
        // 输出true,全部不匹配
        System.out.println(b2);
    }

12.查找元素
查找第一个元素:findFirst,返回Optional类型
查找其中一个元素:findAny,返回Optional类型

public void test4(){
        List<Integer> integers = List.of(124, 2, 15, 12, 51, -5, 5);
        // 输出第一个元素
        Optional<Integer> first = integers.stream().findFirst();
        // 输出结果是Optional[124]
        System.out.println(first);

        System.out.println("-------------");

        List<Integer> integers2 = List.of(124, 2, 15, 12, 51, -5, 5);
        // 返回其中一个元素
        Optional<Integer> any = integers2.stream().findAny();
        System.out.println(any);
    }

13.查找最大最小值(终结方法)

	 /**
     * 查找最大最小值
     */
    @Test
    public void test5(){
        List<Person> list = new ArrayList<>();
        list.add(new Person("马化腾",25,3000));
        list.add(new Person("李彦宏",27,2545));
        list.add(new Person("雷军",35,4515));
        list.add(new Person("马云",55,9877));

        //  查找年龄最大的人
        Optional<Person> max = list.stream().max((e1, e2) -> e1.getAge() - e2.getAge());
        // 返回马云,55岁年龄最大
        System.out.println(max.get());

        System.out.println("--------");

14.规约
是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

public class StreamTest {
	public static void main(String[] args) {
		List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
		// 求和方式1
		Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
		// 求和方式2
		Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
		// 求和方式3
		Integer sum3 = list.stream().reduce(0, Integer::sum);
		
		// 求乘积
		Optional<Integer> product = list.stream().reduce((x, y) -> x * y);

		// 求最大值方式1
		Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
		// 求最大值写法2
		Integer max2 = list.stream().reduce(1, Integer::max);

		System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);
		System.out.println("list求积:" + product.get());
		System.out.println("list求和:" + max.get() + "," + max2);
	}
}

15.收集(终结方法)
将流转化为其他形式,接收一个Collector接口的实现
toList/toSet/toMap。
流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。

public class StreamTest {
	public static void main(String[] args) {
		List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
		List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
		Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());

		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 23, "male", "New York"));
		personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 24, "female", "New York"));
		
		Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
				.collect(Collectors.toMap(Person::getName, p -> p));
		System.out.println("toList:" + listNew);
		System.out.println("toSet:" + set);
		System.out.println("toMap:" + map);
	}
}

16.迭代:iterate
可以使用Stream.iterate创建流值,即所谓的无限流。

//Stream.iterate(initial value, next value)
	Stream.iterate(0, n -> n + 1)
                .limit(5)
                .forEach(x -> System.out.println(x));
0
1
2
3
4    

二、Optional

Java8引入了Optional类来解决NullPointerException的问题。
在这里插入图片描述更多

;