JAVA1.8Stream如何使用_第2页回答

2020-12-31 09:44发布

JAVA1.8Stream如何使用

JAVA1.8Stream如何使用

9条回答
AW
2楼 · 2021-01-20 15:02

tream是Java 1.8版本开始提供的一个接口,主要提供对数据集合使用流的方式进行操作,流中的元素不可变且只会被消费一次,所有方法都设计成支持链式调用。使用Stream API可以极大生产力,写出高效率、干净、简洁的代码。

如何获得Stream实例

Stream提供了静态构建方法,可以基于不同的参数创建返回Stream实例

使用Collection的子类实例调用stream()或者parallelStream()方法也可以得到Stream实例,两个方法的区别在于后续执行Stream其他方法的时候是单线程还是多线程

1
2
3
4
5
6
7
8
9
10
Stream stringStream = Stream.of("1", "2", "3");
//无限长的偶数流
Stream evenNumStream = Stream.iterate(0, n -> n + 2);
 
List strList = new ArrayList<>();
strList.add("1");
strList.add("2");
strList.add("3");
Stream strStream = strList.stream();
Stream strParallelStream = strList.parallelStream();

filter

filter方法用于根据指定的条件做过滤,返回符合条件的流

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//获得只包含正数的流,positiveNumStream -> (1,2,3)
Stream positiveNumStream = numStream.filter(num -> num > 0);

map

map方法用于将流中的每个元素执行指定的转换逻辑,返回其他类型元素的流

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//转换成字符串流
Stream strStream = numStream.map(String::valueOf);

mapToInt mapToLong mapToDouble

这三个方法是对map方法的封装,返回的是官方为各个类型单独定义的Stream,该Stream还提供了适合各自类型的其他操作方法

1
2
3
4
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
IntStream intStream = stringStream.mapToInt(Integer::parseInt);
LongStream longStream = stringStream.mapToLong(Long::parseLong);
DoubleStream doubleStream = stringStream.mapToDouble(Double::parseDouble);

flatMap

flatMap方法用于将流中的每个元素转换成其他类型元素的流,比如,当前有一个订单(Order)列表,每个订单又包含多个商品(itemList),如果要得到所有订单的所有商品汇总,就可以使用该方法,如下:

1
Stream allItemStream = orderList.stream().flatMap(order -> order.itemList.stream());

flatMapToInt flatMapToLong flatMapToDouble

这三个方法是对flatMap方法的封装,返回的是官方为各个类型单独定义的Stream,使用方法同上

distinct

distinct方法用于对流中的元素去重,判断元素是否重复使用的是equals方法

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 0, 1, 2, 2, 3);
//不重复的数字流,uniqueNumStream -> (-2, -1, 0, 1, 2, 3)
Stream uniqueNumStream = numStream.distinct();

sorted

sorted有一个无参和一个有参的方法,用于对流中的元素进行排序。无参方法要求流中的元素必须实现Comparable接口,不然会报java.lang.ClassCastException异常

1
2
3
Stream unorderedStream = Stream.of(5, 6, 32, 7, 27, 4);
//按从小到大排序完成的流,orderedStream -> (4, 5, 6, 7, 27, 32)
Stream orderedStream = unorderedStream.sorted();

有参方法sorted(Comparator comparator)不需要元素实现Comparable接口,通过指定的元素比较器对流内的元素进行排序

1
2
3
Stream unorderedStream = Stream.of("1234", "123", "12", "12345", "123456", "1");
//按字符串长度从小到大排序完成的流,orderedStream -> ("1", "12", "123", "1234", "12345", "123456")
Stream orderedStream = unorderedStream.sorted(Comparator.comparingInt(String::length));

peek

peek方法可以不调整元素顺序和数量的情况下消费每一个元素,然后产生新的流,按文档上的说明,主要是用于对流执行的中间过程做debug的时候使用,因为Stream使用的时候一般都是链式调用的,所以可能会执行多次流操作,如果想看每个元素在多次流操作中间的流转情况,就可以使用这个方法实现

1
2
3
4
5
6
7
8
9
10
11
12
Stream.of("one", "two", "three", "four")
 .filter(e -> e.length() > 3)
 .peek(e -> System.out.println("Filtered value: " + e))
 .map(String::toUpperCase)
 .peek(e -> System.out.println("Mapped value: " + e))
 .collect(Collectors.toList());
  
输出:
Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR

limit(long maxSize)

limit方法会对流进行顺序截取,从第1个元素开始,保留最多maxSize个元素

1
2
3
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//截取前3个元素,subStringStream -> ("-2", "-1", "0")
Stream subStringStream = stringStream.limit(3);

skip(long n)

skip方法用于跳过前n个元素,如果流中的元素数量不足n,则返回一个空的流

1
2
3
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//跳过前3个元素,subStringStream -> ("1", "2", "3")
Stream subStringStream = stringStream.skip(3);

forEach

forEach方法的作用跟普通的for循环类似,不过这个可以支持多线程遍历,但是不保证遍历的顺序

1
2
3
4
5
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//单线程遍历输出元素
stringStream.forEach(System.out::println);
//多线程遍历输出元素
stringStream.parallel().forEach(System.out::println);

forEachOrdered

forEachOrdered方法可以保证顺序遍历,比如这个流是从外部传进来的,然后在这之前调用过parallel方法开启了多线程执行,就可以使用这个方法保证单线程顺序遍历

1
2
3
4
5
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//顺序遍历输出元素
stringStream.forEachOrdered(System.out::println);
//多线程遍历输出元素,下面这行跟上面的执行结果是一样的
//stringStream.parallel().forEachOrdered(System.out::println);

toArray

toArray有一个无参和一个有参的方法,无参方法用于把流中的元素转换成Object数组

1
2
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
Object[] objArray = stringStream.toArray();

有参方法toArray(IntFunction generator)支持把流中的元素转换成指定类型的元素数组

1
2
Stream stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
String[] strArray = stringStream.toArray(String[]::new);

reduce

reduce有三个重载方法,作用是对流内元素做累进操作

第一个reduce(BinaryOperator accumulator)

accumulator 为累进操作的具体计算

单线程等下如下代码

1
2
3
4
5
6
7
8
9
10
11
boolean foundAny = false;
T result = null;
for (T element : this stream) {
 if (!foundAny) {
 foundAny = true;
 result = element;
 }
 else
 result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
1
2
3
4
5
6
7
8
9
10
11
12
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//查找最小值
Optional min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo));
//输出 -2
System.out.println(min.get());
 
//过滤出大于5的元素流
numStream = Stream.of(-2, -1, 0, 1, 2, 3).filter(num -> num > 5);
//查找最小值
min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo));
//输出 Optional.empty
System.out.println(min);

第二个reduce(T identity, BinaryOperator accumulator)

identity 为累进操作的初始值
accumulator 同上

单线程等价如下代码

1
2
3
4
T result = identity;
for (T element : this stream)
 result = accumulator.apply(result, element)
return result;
1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//累加计算所有元素的和,sum=3
int sum = numStream.reduce(0, Integer::sum);

第三个reduce(U identity, BiFunction accumulator, BinaryOperator combiner)

identity和accumulator同上

combiner用于多线程执行的情况下合并最终结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
int sum = numStream.parallel().reduce(0, (a, b) -> {
 System.out.println("accumulator执行:" + a + " + " + b);
 return a + b;
}, (a, b) -> {
 System.out.println("combiner执行:" + a + " + " + b);
 return a + b;
});
System.out.println("最终结果:"+sum);
 
输出:
accumulator执行:0 + -1
accumulator执行:0 + 1
accumulator执行:0 + 0
accumulator执行:0 + 2
accumulator执行:0 + -2
accumulator执行:0 + 3
combiner执行:2 + 3
combiner执行:-1 + 0
combiner执行:1 + 5
combiner执行:-2 + -1
combiner执行:-3 + 6
最终结果:3

collect

collect有两个重载方法,主要作用是把流中的元素作为集合转换成其他Collection的子类,其内部实现类似于前面的累进操作

第一个collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)

supplier 需要返回开始执行时的默认结果

accumulator 用于累进计算用

combiner 用于多线程合并结果

单线程执行等价于如下代码

1
2
3
4
R result = supplier.get();
for (T element : this stream)
 accumulator.accept(result, element);
return result;

第二个collect(Collector collector)

collector其实是对上面的方法参数的一个封装,内部执行逻辑是一样的,只不过JDK提供了一些默认的Collector实现

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
List numList = numStream.collect(Collectors.toList());
Set numSet = numStream.collect(Collectors.toSet());

min

min方法用于计算流内元素的最小值

1
2
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
Optional min = numStream.min(Integer::compareTo);

max

min方法用于计算流内元素的最大值

1
2
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
Optional max = numStream.max(Integer::compareTo);

count

count方法用于统计流内元素的总个数

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//count=6
long count = numStream.count();

anyMatch

anyMatch方法用于匹配校验流内元素是否有符合指定条件的元素

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//判断是否包含正数,hasPositiveNum=true
boolean hasPositiveNum = numStream.anyMatch(num -> num > 0);

allMatch

allMatch方法用于匹配校验流内元素是否所有元素都符合指定条件

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//判断是否全部是正数,allNumPositive=false
boolean allNumPositive = numStream.allMatch(num -> num > 0);

noneMatch

noneMatch方法用于匹配校验流内元素是否都不符合指定条件

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//判断是否没有小于0的元素,noNegativeNum=false
boolean noNegativeNum = numStream.noneMatch(num -> num < 0);

findFirst

findFirst方法用于获取第一个元素,如果流是空的,则返回Optional.empty

1
2
3
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//获取第一个元素,firstNum=-2
Optional firstNum = numStream.findFirst();

findAny

findAny方法用于获取流中的任意一个元素,如果流是空的,则返回Optional.empty,因为可能会使用多线程,所以不保证每次返回的是同一个元素

1
2
Stream numStream = Stream.of(-2, -1, 0, 1, 2, 3);
Optional anyNum = numStream.findAny();


相关问题推荐

  • 回答 156

    对于每一位才开始接触JAVA的新手来说,先不要管算法和数据结构,大多数简单的程序不需要用到算法和数据结构,所以当你真正需要时再去学习。编程一段时间以后,你就会知道在哪些地方用到他们。这时知道算法的名字并了解它们的功能,然后动手去实践。当我们在去...

  • 回答 93

    2个都很好就业,更关键的是要学得到东西

  • 回答 12
    已采纳

    获取Map集合中所有的key可以通过map集合的keySet()方法获取例如:    Map map = new HashMap();    map.put(xx,xx); //存放数据    //.... 省略    Set set = map.keySet();    //可以通过迭代器进行测试    Iterator iter = set.iter...

  • 回答 56
    已采纳

    不同年龄,不同掌握程度,学历,找工作城市,面试能力这是一个多方面影响的结果,如果是平均值的话,全国平均薪资14k左右

  • 回答 38

    具体学多久,根据自己的学习力,自律性、解决问题能力来决定若系统性学习,跟着讲师的节奏走,大概半年左右,有专业的讲师把课程进行规划,尽心系统学习,有问题,讲师会帮忙解决,学习的效率很高,避免了自学中出现各种问题解决不了,而耽误很多时间,可能会...

  • 回答 23
    已采纳

    (1)idea启动时会有两个快捷方式,安装完后默认生成在桌面的是32位的idea的快捷方式,如果我们使用这个快捷方式运行大项目,一般都会很卡。解决方法是找到idea的安装目录,然后进入bin文件夹,找到名称为idea64的应用程序,右键他生成桌面快捷方式。以后每次...

  • Java方法的命名规则2021-04-06 19:07
    回答 31

    ava是一种区分字母的大小写的语言,所以我们在定义变量名的时候应该注意区分大小写的使用和一些规范,接下来我们简单的来讲讲Java语言中包、类、变量等的命名规范。(一)Package(包)的命名Package的名字应该都是由一个小写单词组成,例如com、xuetang9、compan...

  • BIO与NIO、AIO的区别2020-05-19 15:59
    回答 4
    已采纳

    IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。一、BIO     在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要...

  • 回答 2

    public class Point {    private int x;    private int y;    public int getX() {        return x;    }    public void setX(int x) {        this.x = x;    }    public int getY() {        return y;    } ...

  • 回答 6

    经典版单例模式public class Singleton {        private static Singleton uniqueInstance;//利用一个静态常量来记录singleton类的唯一实例。     private Singleton() {     }     public static  Singleton getInstance()...

  • 回答 3

    哈希表的长度一般是定长的,在存储数据之前我们应该知道我们存储的数据规模是多大,应该尽可能地避免频繁地让哈希表扩容。但是如果设计的太大,那么就会浪费空间,因为我们跟不用不到那么大的空间来存储我们当前的数据规模;如果设计的太小,那么就会很容易发...

  • 回答 14

    1. DOM(Document Object Model)        DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才...

  • 回答 19

    1)作用不同: throw用于程序员自行产生并抛出异常; throws用于声明在该方法内抛出了异常2) 使用的位置不同: throw位于方法体内部,可以作为单独语句使用; throws必须跟在方法参数列表的后面,不能单独使用。3)内容不同: throw抛出一个异常对象,且只能是...

  • 回答 11

    基本执行过程如下:1)程序首先执行可能发生异常的try语句块。2)如果try语句没有出现异常则执行完后跳至finally语句块执行;3)如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。4)catch语句块可以有多个,分别捕获不同类型...

  • 回答 20

    100-199 用于指定客户端应相应的某些动作。 200-299 用于表示请求成功。 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。 400-499 用于指出客户端的错误。 400 语义有误,当前请求无法被服务器理解。 401 当前请求需要用户验证...

  • 回答 16

    异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译...

没有解决我的问题,去提问