JDK1.8新特性复习

JDK1.8新特性

1、Lambda表达式

2、::运算符引用方法

3、stream

Stream是JDK1.8新增的一个特性,称之为Stream,它可以给予Lamdba表达式对集合数据进行处理(如:遍历、排序、去重、修改)等操作,并且支持同时使用2种或以上的操作。

Stream流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算。

3.1、创建Stream

3.1.1、使用Stream提供的方法创建

3.1.1.1、of方法创建
// 不仅可以使用int,也可以是对象、Map、Object。。。。
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
// 使用对象创建
Stream<Person> integerStream = Stream.of(person1, person2);
3.1.1.2、iterate方法创建

iterate的第一个参数为n的值,第二个参数是一个lambda表达式,返回一个值提供给Stream,由于这个流是无限的,所以需要使用limit方法进行截取,这个方法的具体用法可以参考3.2.5。

Stream<Integer> limit = Stream.iterate(1, n -> n + 2).limit(5);
3.1.1.3、generator方法创建

generator方法和iterate类似,只是lambda表达式的类型不一样,它的lambda表达式没有参数,只有返回值。这个流也是无限的,所以需要使用limit方法进行截取,这个方法的具体用法可以参考3.2.5。

Stream<Double> limit = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);

3.1.2、使用集合创建

// 使用of方法创建
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.add(4);
integers.add(5);
Stream<Integer> interStream = integers.stream();

3.1.3、使用Array创建

// 使用of方法创建
Integer[] integerArray = {1,3,5,7,9};
Stream<Integer> stream = Arrays.stream(integerArray);

3.1.4、使用文件创建

通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行

try {
  Stream<String> fileStream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
} catch (IOException e) {
  e.printStackTrace();
}

3.2、中间操作符

通常对于Stream的中间操作,可以视为是源的查询,并且是懒惰式的设计,对于源数据进行的计算只有在需要时才会被执行,与数据库中视图的原理相似;

Stream流的强大之处便是在于提供了丰富的中间操作,相比集合或数组这类容器,极大的简化源数据的计算复杂度

一个流可以跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用

这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时,常见的中间操作有下面即将介绍的 filter、map 等

3.2.1、filter方法

通过设置的条件过滤元素

// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
// 先筛选大于50的,再进行遍历
stream.filter(v->v>50).forEach(System.out::println);

打印结果:

76.0
75.0
71.0
90.0
81.0

可以看到,原本十个随机数经过过滤后只剩下五个大于50的~

3.2.2、map方法

map元素可以对集合进行遍历,并且对每个元素进行修改后返回一个新的stream

// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.filter(v->v>50).map(v->v+50).forEach(System.out::println);

打印结果:

125.0
144.0
105.0
146.0
119.0
149.0

从上面的结果可以看出,stream的方法是有顺序的,其实是一个链式调用,先对结果进行flter返回一个新的stream,再对这个新的stream修改后返回一个新的stream。

调换fiter和map的顺序再次执行

// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>50).forEach(System.out::println);

输出结果:

72.0
105.0
115.0
128.0
129.0
128.0
78.0
68.0
134.0
51.0

3.2.3、distinct方法

这个方法如单词含义一样,是用来去重的。对于Object的子类,是根据元素的hashCode和equels方法来实现的对比。所以要根据使用场景重写这两个方法。

// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 2)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>=50).distinct().forEach(System.out::println);

输出结果:

51.0
50.0

3.2.4、sorted方法

此方法用来排序,返回排序后的流。

// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 2)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>=50).distinct().sorted().forEach(System.out::println);

输出:

50.0
51.0

从运行结果可以看出它默认采取的是升序排序,如果想自定义查询规则,也可以调用sorted的重载方法,传递一个Comparator Lambda表达式。

// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 5)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>=50).distinct().sorted((o1,o2)-> (int)Math.round(o2-o1)).forEach(System.out::println);

输出:

54.0
53.0
52.0
51.0
50.0

3.2.5、limit方法

会返回一个不超过给定长度的流,实际上我们上面的案例都已经用过这个方法了,下面再次演示一下limit“截取”流。

Stream.of(1,2,3,4,5,6,7,8,9,0).limit(4).forEach(System.out::println);

输出:

1
2
3
4

3.2.6、skip方法

如词义一样,这个方法用来跳过某个元素,如果说limit是截取后面的元素,那么skip就是截取前面的元素。

Stream.of(1,2,3,4,5,6,7,8,9,0).limit(4).skip(2).forEach(System.out::println);

输出:

3
4

3.2.7、flatMap方法

这个方法我的理解是,将流内存储的每个元素再转换为流,然后合并为一个流。

测试数据,下文都是使用此测试数据

ArrayList<Integer> arrayList1 = new ArrayList();
arrayList1.add(1);
arrayList1.add(2);
ArrayList<Integer> arrayList2 = new ArrayList();
arrayList2.add(3);
arrayList2.add(4);
ArrayList<Integer> arrayList3 = new ArrayList();
arrayList3.add(5);
arrayList3.add(6);

合并流

// 合并流
Stream.of(arrayList1,arrayList2,arrayList3)
  .flatMap(arrayList -> arrayList.stream()).forEach(System.out::println);

输出:

1
2
3
4
5
6

同时还可以对这个合并后的流进行一系列操作。

// 合并后把买个元素+1再输出
Stream.of(arrayList1,arrayList2,arrayList3)
  .flatMap(arrayList->arrayList.stream().map(value->value+1))
  .forEach(System.out::println);

输出:

2
3
4
5
6
7

3.2.8、peek方法

对Stream内的元素进行遍历处理,如果是引用类型,遍历的过程中可以对属性进行编辑,非引用类型的只能修改形参,不过可以在其lambda表达式内进行改变和测试。peek的操作是返回一个新的stream的,且设计的初衷是用来debug调试的,因此使用steam.peek()必须对流进行一次处理再产生一个新的stream

// peek可以对元素进行遍历,但是不能进行修改
Stream.of(arrayList1,arrayList2,arrayList3)
  .flatMap(arrayList -> arrayList.stream())
  .peek(v->{ v=v+1; }).forEach(System.out::println);

输出:

1
2
3
4
5
6

3.3、终端操作符

Stream流执行完终端操作之后,无法再执行其他动作,否则会报状态异常,提示该流已经被执行操作或者被关闭,想要再次执行操作必须重新创建Stream流

一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流。

终端操作的执行,才会真正开始流的遍历。如 count、collect 等

3.3.1、collect方法

收集器,将流转换为其他形式,下面介绍两种比较常见的场景,它还有一些其他的功能,例如转换的时候可以做最大值、最小值、平均值、总和值、总数等操作。

转换为List:

List<Integer> collect = Stream.of(arrayList1, arrayList2, arrayList3)
  .flatMap(arrayList -> arrayList.stream()).peek(v -> {v = v + 1;})
  .collect(Collectors.toList());

转换为Map,转换时需要提供k,v的生成策略,都是根据Lambda表达式生成:

Map<String, Integer> collect = Stream.of(arrayList1, arrayList2, arrayList3)
.flatMap(arrayList -> arrayList.stream())
				.peek(v -> {
            v = v + 1;
        }).collect(Collectors.toMap(k -> "key" + k, v -> v));


        collect.forEach((k,v)->{
            System.out.println("key:"+k+",v:"+v);
        });

输出:

key:key1,v:1
key:key2,v:2
key:key5,v:5
key:key6,v:6
key:key3,v:3
key:key4,v:4

3.3.2、forEach方法

遍历流,这个方法上面已经演示很多次了就不再演示了,需要注意的是,如果是在中途需要遍历可以使用peek,因为forEach是终止操作符。

3.3.3、findFirst方法

返回第一个元素,默认返回Optional,可以使用get返回元素。Optional内内置了一些方法可以对存储的元素进行过滤,遍历等操作。

// 取出第一个元素
Optional<ArrayList<Integer>> first = Stream.of(arrayList1, arrayList2, arrayList3).findFirst();
// 取出元素
ArrayList<Integer> integers = first.get();

3.3.4、findAny方法

返回流中所有元素

// 取出所有元素
Optional<ArrayList<Integer>> first = Stream.of(arrayList1, arrayList2, arrayList3).findAny();
// 取出元素
ArrayList<Integer> integers = first.get();
System.out.println(integers);

返回:

[1, 2]

3.3.5、count方法

返回元素个数

// 取出所有元素
long count = Stream.of(arrayList1, arrayList2, arrayList3,null).filter(v->v!=null).count();
// 打印结果
System.out.println(count);

返回:

3

3.3.6、sum方法

求和,这个方法必须配合mapToInt、mapToLong等方法一起使用,下面介绍如何求集合内所有元素的和

// 取出所有元素
long count = Stream.of(arrayList1, arrayList2, arrayList3, null)
  .filter(v -> v != null)
  .mapToInt(v -> v.stream().mapToInt(item->item).sum()).sum();
// 打印结果
System.out.println(count);

返回:

21

3.3.7 、max方法

求最大值,需要指定根据什么比较,比如这个是根据长度比较,

// 指定比较的对象是什么
ArrayList<Integer> integers = Stream.of(arrayList1, arrayList2, arrayList3)
  .max(Comparator.comparingInt(value -> value.size())).get();

// 打印结果
System.out.println(integers.size());

输出:3

下面是先合并为一个大的集合,再根据元素内容比较

// 求最大值
        Integer max = Stream.of(arrayList1, arrayList2, arrayList3).flatMap(v -> v.stream()).max(Comparator.comparingInt(value -> value)).get();

        // 打印结果
        System.out.println(max);

输出:6

3.3.8、min方法

求最小值,用法与max相似,这里就不再演示了。

3.3.9、anyMatch方法

检查是否包含某个元素

// 是否符合个条件
boolean b = Stream.of(arrayList1, arrayList2, arrayList3).flatMap(v -> v.stream()).anyMatch(v -> v == 0);

// 打印结果
System.out.println(b);

输出:false

3.3.10、allMatch方法

检查所有元素是否都符合条件,与3.3.9方法类似,这里就不演示了。

3.3.11、noneMatch方法

检查是否有不满足条件的,与3.3.9类似,这里就不演示了

3.3.12、reduce方法

可以将流中元素反复结合起来,得到一个值,这里的reduce虽然只有两个参数,但是并非只会执行一次,而是会将参数依次代入执行。

// 结合
ArrayList<Integer> integers = Stream.of(arrayList1, arrayList2, arrayList3)
  .reduce((obj1, obj2) -> {
    obj1.addAll(obj2);
    return obj1;
  }).get();

// 打印结果
System.out.println(integers);

输出:

[1, 2, 3, 4, 5, 6]

3.4、Collect收集

Collector:结果收集策略的核心接口,具备将指定元素累加存放到结果容器中的能力;并在Collectors工具中提供了Collector接口的实现类

3.4.1、toList

将用户ID存放到List集合中

List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ;

3.4.2、toMap

将用户ID和Name以Key-Value形式存放到Map集合中

Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));

3.4.3、toSet

将用户所在城市存放到Set集合中

Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet());

3.4.4、counting

符合条件的用户总数

long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());

3.4.5、summingInt

对结果元素即用户ID求和

Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;

3.4.6、minBy

筛选元素中ID最小的用户

User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;

3.4.7、joining

将用户所在城市,以指定分隔符链接成字符串;

String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));

3.4.8、groupingBy

按条件分组,以城市对用户进行分组;

Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));

3.4.9、orElse(null)

    /**
     * Return the value if present, otherwise return {@code other}.
     *
     * @param other the value to be returned if there is no value present, may
     * be null
     * @return the value, if present, otherwise {@code other}
     * 返回值,如果存在,否则返回其他
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

表示如果一个都没找到返回null(orElse()中可以塞默认值。如果找不到就会返回orElse中设置的默认值)

3.4.10、orElseGet(null)

    /**
     * Return the value if present, otherwise invoke {@code other} and return
     * the result of that invocation.
     *
     * @param other a {@code Supplier} whose result is returned if no value
     * is present
     * @return the value if present otherwise the result of {@code other.get()}
     * @throws NullPointerException if value is not present and {@code other} is
     * null
     * 返回值如果存在,否则调用其他值并返回该调用的结果
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

表示如果一个都没找到返回null(orElseGet()中可以塞默认值。如果找不到就会返回orElseGet中设置的默认值)

orElse() 接受类型T的 任何参数,而orElseGet()接受类型为Supplier的函数接口,该接口返回类型为T的对象

3.4.10、orElse(null)和orElseGet(null)区别:

1、当返回Optional的值是空值null时,无论orElse还是orElseGet都会执行

2、而当返回的Optional有值时,orElse会执行,而orElseGet不会执行

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class TestStream {

    public static void main(String[] args) {

        List<User> list = new ArrayList<>();

        //定义三个用户对象
        User user1 = new User();
        user1.setUserName("admin");
        user1.setAge(16);
        user1.setSex("男");
        User user2 = new User();
        user2.setUserName("root");
		    user2.setAge(20);
        user2.setSex("女");
        User user3 = new User();
        user3.setUserName("admin");
        user3.setAge(18);
        user3.setSex("男");
        User user4 = new User();
        user4.setUserName("admin11");
        user4.setAge(22);
        user4.setSex("女");
        //添加用户到集合中
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);
        /*
        在集合中查询用户名包含admin的集合
        */

        List<User> userList = list.stream().filter(user -> user.getUserName().contains("admin")&& user.getAge() <= 20).collect(Collectors.toList());
        System.out.println(userList);

        /*
        在集合中查询出第一个用户名为admin的用户
        */

        Optional<User> user = list.stream().filter(userTemp -> "admin".equals(userTemp.getUserName())).findFirst();

        System.out.println(user);

        /*
        orElse(null)表示如果一个都没找到返回null(orElse()中可以塞默认值。如果找不到就会返回orElse中设置的默认值)
        orElseGet(null)表示如果一个都没找到返回null(orElseGet()中可以塞默认值。如果找不到就会返回orElseGet中设置的默认值)
        orElse()和orElseGet()区别:在使用方法时,即使没有值 也会执行 orElse 内的方法, 而 orElseGet则不会
        */
        //没值
        User a =  list.stream().filter(userT-> userT.getAge() == 12).findFirst().orElse(getMethod("a"));
        User b =  list.stream().filter(userT11-> userT11.getAge() == 12).findFirst().orElseGet(()->getMethod("b"));

        //有值
        User c =  list.stream().filter(userT2-> userT2.getAge() == 16).findFirst().orElse(getMethod("c"));
        User d =  list.stream().filter(userT22-> userT22.getAge() == 16).findFirst().orElseGet(()->getMethod("d"));


        System.out.println("a:"+a);
        System.out.println("b:"+b);
        System.out.println("c:"+c);
        System.out.println("d:"+d);
    }

    public static User getMethod(String name){

        System.out.println(name + "执行了方法");
        return null;
    }
}

4、Optional

5、新的日期格式

6、其他特性

参考:Java--Stream流详解,后面相当一部分是直接粘贴的,基本等于转载了~,大家可以看看原文哦

posted @ 2023-02-18 23:55  张瑞丰  阅读(77)  评论(0编辑  收藏  举报