java8根据某个字段过滤并拼接_侠说java8--Stream流操作学习
笔记,都在这⾥了
前⾔
⾸次接触到Stream的时候以为它是和InputStream、OutputStream这样的输⼊输出流的统称。
流和集合的前世今⽣
概念的差异
在开发中,我们使⽤最多的类库之⼀就是集合。集合是⼀种内存中的数据结构,⽤来保存对象数据,集合中的每个元素都得先算出来才能添加到集合中,相⽐之下:
集合⽤特定数据结构(如List,Set或Map)存储和分组数据。但是,流⽤于对存储的数据(例如数组,集合或I / O资源)执⾏复杂的数据处理操作,例如过滤,匹配,映射等。由我们可以知道:
集合主要是存储数据,⽽流主要关注对数据的操作。
数据修改
我们可以添加或删除集合中的元素。但是,不能添加或删除流中的元素。流是通过消费数据源的⽅式,对其执⾏操作并返回结果。它不会修改数据源头。
内部迭代和外部迭代
Java8提供的 Streams的主要特点是我们不必担⼼使⽤流时的迭代。流在后台为我们内部执⾏迭代。我们只需关注在数据源上需要执⾏哪些操作即可。
循环遍历
流只能遍历⼀次。如果你遍历该流⼀次,则将其消耗掉。要再次遍历它,必须再次从数据源中获取新的流。但是,集合可以遍历多次。
惰性求值(懒汉or饿汉)
相信⼤家都知道单例模式中的两种模式,懒汉式和饿汉式,在这⾥也可以相似的理解。
集合以饿汉式迅速的构建,即是所有元素都在开始时就进⾏了计算。但是,流是延迟构造的,即在调⽤终端操作之前不会去计算中间操作,也就是惰性求值(懒汉式)。
特性解读
两种迭代⽅式
上⾯我们提到了两种迭代的⽅式,内部迭代和外部迭代,怎么来理解呢?在java8之前,我们⽤的for循序,其实就是外部迭代,显⽰的去循环集合中的每⼀个元素。
⽽内部迭代则是,Stream内部帮我们做了这个操作,并且它还把流的值放到了某个地⽅,我们只需要给出相应的指令
(map/flatmap/filter),指挥它就⾏。
中间操作和终端操作
在java8中,我们可以把中间操作认为是⼯⼚流⽔线上的⼀个⼯⼈,它将产品加⼯过后,返回⼀个新的东西(流),⼀个新的流。它会让多个操作可以连接起来,⼀旦流⽔线上触发⼀个终端操作就会执⾏处理。
惰性 求值的理解
上⾯提到的两种操作其实就是惰性求值的解读。中间操作⼀般都可以合并起来,在终端操作时⼀次性全部处理求值。在处理更⼤的数据或流操作很多时,惰性求值是真正的福⾳。
因为处理数据时,我们不确定如何使⽤处理后的数据。直接循环⼀个很⼤的集合将始终以性能为代价⽽告终,其实客户端可能只是最终会利⽤其中的⼀⼩部分。或者,根据某些条件过滤⼀下,它可能甚⾄不需要利⽤该数据。惰性求值处理基于按需 策略来帮助我们实现业务功能。
Stream操作案例
String类上提供了有两个新⽅法:join和chars,使⽤join拼接字符串⾮常⽅便。
String.join(":", "foobar", "foo", "bar");
// => foobar:foo:bar
第⼆种⽅法chars为字符串的所有字符创建流,可以对这些字符使⽤流操作:
"foobar:foo:bar"
.
chars()
.distinct()
.mapToObj(c -> String.valueOf((char)c))
.sorted()
.collect(Collectors.joining());
// => :abfor
处理⽂件Files最初是在Java 7中作为Java NIO的⼀部分引⼊的。JDK 8 API添加了⼀些其他⽅法,使我们能够对⽂件使⽤功能流。
try (Stream<Path> stream = Files.(""))) {
String joined = stream
.map(String::valueOf)
.filter(path -> !path.startsWith("."))
.sorted()
.collect(Collectors.joining("; "));
System.out.println("List: " + joined);
}
上⾯的⽰例列出了当前⼯作⽬录的所有⽂件,然后将每个路径映射到其字符串表⽰形式。然后将结果过滤,排序并最终加⼊⼀个字符串中。
细⼼的你您可能已经注意到,流的创建被包装在try / with语句中。流实现了AutoCloseable,在这种情况下,由于有IO操作⽀持,因此我们确实必须显式关闭流。
查⽂件
Path start = ("");
int maxDepth = 5;
try (Stream<Path> stream = Files.find(start, maxDepth, (path, attr) ->
String.valueOf(path).endsWith(".js"))) {
String joined = stream
.sorted()
.map(String::valueOf)
.collect(Collectors.joining("; "));
System.out.println("Found: " + joined);
}
该⽅法find接受三个参数:⽬录路径start是初始起点,并maxDepth定义了要搜索的最⼤⽂件夹深度。第三个参数是匹配谓词,它定义搜索逻辑。在上⾯的⽰例中,我们搜索所有JavaScript⽂件(⽂件名以.js结尾)。
读写⽂件
List<String> lines = ("res/nashorn1.js"));
lines.add("print('foobar');");
Files.("res/nashorn1-modified.js"), lines);
⽤Java 8将⽂本⽂件读⼊内存并将字符串写⼊⽂本⽂件。这些⽅法的内存效率不是很⾼,因为整个⽂件都将被读取到内存中。⽂件越⼤,将使⽤越多的堆⼤⼩。
使⽤流的注意事项
注意,流只能使⽤⼀次。
public static void main(String[] args) {
String[] array = {"a", "b", "c", "d", "e"};
Stream<String> stream = Arrays.stream(array);
// 消费流
stream.forEach(x -> System.out.println(x));
// 重⽤流! throws IllegalStateException
long count = stream.filter(x -> "b".equals(x)).count();
System.out.println(count);
}
正确的使⽤⽅式
public static void main(String[] args) {
String[] array = {"a", "b", "c", "d", "e"};
Supplier<Stream<String>> streamSupplier = () -> Stream.of(array);
//获取新的流
<().forEach(x -> System.out.println(x));
//获取另⼀个流
long count = ().filter(x -> "b".equals(x)).count();
System.out.println(count);
}
过滤空值
Stream<String> language = Stream.of("java", "python", "node", null, "ruby", null, "php");        //List<String> result = List());
//使⽤filter过滤空值
List<String> result = language.filter(x -> x!=null).List());
result.forEach(System.out::println);
map映射操作
List<String> alpha = Arrays.asList("a", "b", "c", "d");
//Java8前
List<String> alphaUpper = new ArrayList<>();
for (String s : alpha) {
alphaUpper.UpperCase());
}
System.out.println(alpha); //[a, b, c, d]
System.out.println(alphaUpper); //[A, B, C, D]
// Java 8
List<String> collect = alpha.stream().map(String::toUpperCase).List());        System.out.println(collect); //[A, B, C, D]
filter过滤对象数组// map映射操作
List<Integer> num = Arrays.asList(1,2,3,4,5);
List<Integer> collect1 = num.stream().map(n -> n * 2).List());
System.out.println(collect1); //[2, 4, 6, 8, 10]
分组,计数、排序
//3 apple, 2 banana, others 1
List<String> items =
Arrays.asList("apple", "apple", "banana",
"apple", "orange", "banana", "papaya");
Map<String, Long> result =
items.stream().collect(
Function.identity(), unting()
)
);
Map<String, Long> finalMap = new LinkedHashMap<>();
//map排序
.sorted(Map.Entry.<String, Long>comparingByValue()
.reversed()).forEachOrdered(e -> finalMap.Key(), e.getValue()));
System.out.println(finalMap);
总结
本篇⽂章记录了Stream流操作的⼀些知识点。来检测⼀下,以下问题你是不是都会了呢?
Stream流和集合的区别?
解释内部循环和外部循环?
解释⼀下惰性求值?
Stream的常⽤操作有哪些?
欢迎来侠梦的开发笔记,⼀起讨论交流

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。