Skip to main content
 首页 » 编程设计

java stream 操作

2022年07月19日121kerrycode

java8 stream 操作

Filter

Filter方法接收predicate接口参数,过滤流中所有元素。该操作属于中间操作,所以可以在结果上继续调用其他的流操作(如forEach)。ForEach接收consumer,在流过滤后的每个元素上执行consumer。ForEach是终止操作,返回void,不能调用其他流操作。

  
 
stringCollection 
    .stream() 
    .filter((s) ->s.startsWith("a")) 
    .forEach(System.out::println); 
 
// "aaa2", "aaa1"


Sorted

Sorted是中间操作,返回顺序排列的流视图,元素安装默认的方式排序,除非你传递特定的比较器。

stringCollection 
    .stream() 
    .sorted() 
    .filter((s) -> s.startsWith("a")) 
    .forEach(System.out::println); 
 
// "aaa1", "aaa2"


注意,sorted仅仅返回流视图,并没有真正操作后面集合的顺序,集合的顺序没有受任何影响。

System.out.println(stringCollection); 
 
// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1

 

Map

map属于中间操作,它通过传递的函数转换每个元素。下面示例转换每个字符串值大写形式。也可以使用map转换每个对象至另一种类型。返回类型取决于传递函数的泛型类型。

stringCollection 
    .stream() 
    .map(String::toUpperCase) 
    .sorted((a, b) -> b.compareTo(a)) 
    .forEach(System.out::println); 
  
 
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"

 

Match

几个匹配操作常用检查指定predicate匹配情况,所有匹配操作都是终止操作,返回布尔结果。

boolean anyStartsWithA = 
    stringCollection 
        .stream() 
        .anyMatch((s) -> s.startsWith("a")); 
  
 
System.out.println(anyStartsWithA);      // true 
 
 
boolean allStartsWithA = 
    stringCollection 
        .stream() 
        .allMatch((s) -> s.startsWith("a")); 
  
 
System.out.println(allStartsWithA);      // false 
 
  
boolean noneStartsWithZ = 
    stringCollection 
        .stream() 
        .noneMatch((s) -> s.startsWith("z")); 
 
 
System.out.println(noneStartsWithZ);      // true


Count

count是终止操作,返回流中元素数量。

long startsWithB = 
    stringCollection 
        .stream() 
        .filter((s) -> s.startsWith("b")) 
        .count(); 
 
 
System.out.println(startsWithB);    // 3


Reduce

terminal是终止操作,根据指定函数在流元素上执行reduction操作,返回Optional对象,包括执行结果。

Optional<String> reduced = 
    stringCollection 
        .stream() 
        .sorted() 
        .reduce((s1, s2) -> s1 + "#" + s2); 
 
  
reduced.ifPresent(System.out::println); 
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"


Parallel Streams

上面提到流可以是顺序的或并行的;顺序流操作是单线程执行,而并行流操作属于多线程执行。下面示例演示使用并行流提升性能,非常简单。首先创建list,包含大数据量的不重复元素。

int max = 1000000; 
 
List<String> values = new ArrayList<>(max); 
 
for (int i = 0; i < max; i++) { 
    UUID uuid = UUID.randomUUID(); 
    values.add(uuid.toString()); 
 
}


现在我们测量针对该集合流排序所化的时间。

Sequential Sort

long t0 = System.nanoTime(); 
 
long count = values.stream().sorted().count(); 
System.out.println(count); 
 
 
long t1 = System.nanoTime(); 
 
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); 
 
System.out.println(String.format("sequential sort took: %d ms", millis)); 
 
  
// sequential sort took: 899 ms


Parallel Sort

long t0 = System.nanoTime(); 
 
 
long count = values.parallelStream().sorted().count(); 
 
System.out.println(count); 
 
long t1 = System.nanoTime(); 
 
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); 
 
System.out.println(String.format("parallel sort took: %d ms", millis)); 
 
// parallel sort took: 472 ms


可以看两端代码几乎相同,但是并行流操作几乎快乐50%。所以你当然要使用并行流代替顺序流。

Map

前面提到,map不支持流。想法map提供了几个新的、有用的方法实现通用任务。

Map<Integer, String> map = new HashMap<>(); 
 
 
for (int i = 0; i < 10; i++) { 
 
    map.putIfAbsent(i, "val" + i); 
 
} 
 
map.forEach((id, val) -> System.out.println(val));


 
 上面代码不解自明,putIfAbsent无需我们写额外的null检查;forEach接收consumer针对map的每个值进行操作。示例看map的使用函数。

map.computeIfPresent(3, (num, val) -> val + num); 
 
map.get(3);             // val33 
 
map.computeIfPresent(9, (num, val) -> null); 
map.containsKey(9);     // false 
map.computeIfAbsent(23, num -> "val" + num); 
map.containsKey(23);    // true 
 
map.computeIfAbsent(3, num -> "bam"); 
 
map.get(3);             // val33


接下来,我们学习如何根据指定的key删除entry,仅当正确的映射指定的值。

map.remove(3, "val3"); 
 
map.get(3);             // val33 
 
map.remove(3, "val33"); 
 
map.get(3);             // null


另一个有用的方法:

map.getOrDefault(42, "not found");  // not found 
 
Merging entries of a map is quite easy: 
 
map.merge(9, "val9", (value, newValue) -> value.concat(newValue)); 
 
map.get(9);             // val9 
 
map.merge(9, "concat", (value, newValue) -> value.concat(newValue)); 
 
map.get(9);             // val9concat


merge方法判断,如果key没有对应的entry,则key/value加入map,否则merge参数对应函数被调用改变对应的值。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/52982919
阅读延展