Tec*_*ool 2 java java-8 java-stream collectors
我是 Java 8 Streams和Collectors类的新手。
我正在读取一个文件,其内容需要保存在一个文件中LinkedHashMap<Integer, String>,其中它<keys>是文件的行号,它<values>是每行的内容。
在这里,我想使用这个Stream概念,但我无法使用Collectors.toMap自动递增<keys>,它需要保存在LinnkedHashMap对象中。相反,我得到了例外。
以下是我正在尝试的代码:
List<String> list = new ArrayList<>();
Integer count = 0;
try (BufferedReader br = Files.newBufferedReader( Paths.get( fileName ) )) {
// br returns as stream and convert it into a List
list = br.lines().collect( Collectors.toList() );
}
catch ( IOException e ) {
e.printStackTrace();
}
list.forEach( System.out::println );
Map<Integer, String> fileNumWithContentMapper = list.stream()
.collect( Collectors.toMap( n->n+1,s1->s1));
Run Code Online (Sandbox Code Playgroud)
有很多方法可以做到这一点。但在这里我将解释我的方法:
IntStream。首先,只要你有一个List<E>of 对象(即E可以是String、Integers、Objects等),你就可以Map<Integer, E>使用IntStream类将其转换为 a 。此类是原始 int 值元素的序列,支持顺序和并行聚合操作。这意味着就像一个巨大的计数器。如果我们已经有一个计数器,我们需要设置一些限制,该IntStream.range(int start, int end)方法将对我们有所帮助。IntStream此方法将返回一个从start(包含)到(不包含)的顺序,end增量为 1。因此,如果您想创建一个 IntStream与我们的大小相同的值,List请使用以下命令:
List<Integer> numbers = Arrays.asList(4, 5, 4, 3);
IntStream stream = IntStream.range(0, numbers.size);
Run Code Online (Sandbox Code Playgroud)
Stream2、根据对象准备一个对象IntStream。现在,我们有一个与您的大小相同的计数器List<E>,但我们需要一个Map<Integer, E>. 好吧,现在我们要使用IntStream.boxed(). 此方法返回由Stream该流的元素组成的,每个元素装箱到一个Integer. 这是一个Stream<Integer>。我们快完成了。
Stream<Integer> streamBoxed = stream.boxed();
Run Code Online (Sandbox Code Playgroud)
Stream对象转换为Map对象最后,我们可以使用该方法创建地图Stream.collect()。此方法对此流的元素执行可变归约操作。如果我们没有Collectors.toMap()方法的帮助,这个还原将会很复杂。该收集器可用于将 Stream 元素收集到 Map 实例中。为此,我们需要提供两个函数:keyMapper和valueMapper。将keyMapper用于Map从Stream元素中提取键,并将valueMapper用于提取<value>与给定 关联的<key>。对于我们的示例,我们将使用Map<Integer, Integer>. 我们可以使用 提取流keyMapper的值,并且应该是我们将获得的列表的值,使用如下:steamBoxedi -> ivalueMappernumbersi -> numbers.get(i)
Map<Integer, Integer> result = streamBoxed.collect(Collectors.toMap(i -> i, i -> numbers.get(i)))
Run Code Online (Sandbox Code Playgroud)
这三个部分可以在这个简单的代码中组合在一起:
List<Integer> numbers = Arrays.asList(4, 5, 4, 3);
Map<Integer, Integer> result = IntStream
.range(0, numbers.size); // IntStream
.boxed(); // Stream<Integer>
.collect(Collectors.toMap(i -> i, i -> numbers.get(i))) // Map<Integer, Integer>
Run Code Online (Sandbox Code Playgroud)
另外,您会发现一些作者更喜欢将Function.identity()方法用作keyMapper,并将numbers::getlambda 表达式用作valueMapper。他们为什么使用这些表达方式?只是为了偏好。该Function.identity()方法将始终返回相同的实例。因此,使用Function.identity()noti -> i可能会节省一些内存。但是,i -> i比但更具可读性,Function.identity()因为创建自己的实例并具有不同的实现类会消耗更多内存。lambda表达式::只是一个方法引用捕获。
嗯,像这样:
final List<String> list;
...
// list initialization;
list = br.lines().collect(Collectors.toList());
...
Map<Integer, String> fileNumWithContentMapper = IntStream
.range(0, list.size()) // IntStream
.boxed() // Stream<Integer>
.collect(Collectors.toMap(i -> i, i -> list.get(i))); // Map<Integer, String>
Run Code Online (Sandbox Code Playgroud)
选择
final List<String> list;
...
// list initialization;
list = br.lines().collect(Collectors.toList());
...
Map<Integer, String> fileNumWithContentMapper = IntStream
.range(0, list.size()) // IntStream
.boxed() // Stream<Integer>
.collect(Collectors.toMap(Function.identity(), list::get)) // Map<Integer, String>
Run Code Online (Sandbox Code Playgroud)