在Java 8中,Stream类实现了AutoCloseable.这意味着应该显式关闭流实例.
我理解为什么文件处理程序和数据库连接是可关闭的.但为什么流?
我目前正在学习如何使用Java,我的朋友告诉我,使用Java 8时可以简化这段代码.他指出parseIntArray可以简化.你会如何在Java 8中做到这一点?
public class Solution {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String[] tokens = input.nextLine().split(" ");
int[] ints = parseIntArray(tokens);
}
static int[] parseIntArray(String[] arr) {
int[] ints = new int[arr.length];
for (int i = 0; i < ints.length; i++) {
ints[i] = Integer.parseInt(arr[i]);
}
return ints;
}
}
Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
Path directory = Paths.get(/* some directory */);
Files.list(directory).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
终端操作(如forEach)是否关闭已打开的基础文件?
请参阅Files.list的javadoc的相关部分:
返回的流封装了DirectoryStream.如果需要及时处理文件系统资源,则应使用try-with-resources构造来确保在流操作完成后调用流的close方法.
如果它没有调用Stream.close(),那么在生成可维护代码时调用它的最佳选择是什么?
我在使用jre1.8.0_66的代码运行中遇到这个奇怪的异常:
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
at main
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Object; not a subtype of implementation type interface Fruit
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 3 more
Run Code Online (Sandbox Code Playgroud)
这是什么意思?代码如下:
public static interface Fruit {
int getPickingMonth();
}
public static class Apple implements Fruit, Serializable {
@Override
public int getPickingMonth() {
return 11;
}
}
public static class Orange implements Fruit, Serializable {
@Override
public int …Run Code Online (Sandbox Code Playgroud) 假设我有一个清单
ArrayList<String> arr = new ArrayList(Arrays.asList("N1", "N2", "N3", "N5"));
Run Code Online (Sandbox Code Playgroud)
我怎么找到"N4",我的意思是,我怎么发现丢失的整数是4?
到目前为止我尝试过的
Integer missingID = arr.stream().map(p -> Integer.parseInt(p.substring(1))).sorted()
.reduce((p1, p2) -> (p2 - p1) > 1 ? p1 + 1 : 0).get();
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为reduce在这种情况下不打算以我需要的方式工作,实际上,我不知道怎么做.如果没有丢失的数字,则必须是下一个"N6" - or just 6 -(在此示例中)
它必须使用java标准流的库,不使用第三方.
以下代码工作正常:
Stream.of("key1", "key2")
.map(key -> {
SomeObject foo = service.find(key);
if (foo == null) {
throw new RuntimeException("No entity found with key: " + key);
}
return foo;
})
// ...
Run Code Online (Sandbox Code Playgroud)
但是,当我从Optional使用orElseThrow时:
Stream.of("key1", "key2")
.map(key -> Optional.ofNullable(someService.find(key))
.orElseThrow(() -> new RuntimeException("No entity found with key: " + key)))
// ...
Run Code Online (Sandbox Code Playgroud)
我得到一个编译时错误:
错误:(129,33)java:未报告的异常X; 必须被抓住或宣布被抛出
两者都抛出一个RuntimeException,为什么使用Optional的方法不起作用的任何想法?
更新:我的构建基础架构,我尝试使用IntelliJ和Maven编译它:
$ mvn -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T17:41:47+01:00)
Maven home: C:\Tools\apache-maven-3.3.9
Java version: 1.8.0_91, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_91\jre
Default locale: de_AT, …Run Code Online (Sandbox Code Playgroud) 我是懒惰评估概念的新手.当我在Scala中执行这行代码时;
"12334".grouped(1).toStream.filter{n => println("n:" +n ); n=="3";}
Run Code Online (Sandbox Code Playgroud)
打印出来:
n:1
n:2
n:3
Run Code Online (Sandbox Code Playgroud)
但是当我在Java中运行类似的东西时,例如:
List<String> myList = new ArrayList<>(Arrays.asList("12334".split("")));
Stream<String> myList2 = myList.stream().filter(a -> {System.out.println("a:" +a);return "3".equals(a);});
Run Code Online (Sandbox Code Playgroud)
它无声地终止,无需向控制台行写任何内容.Java的行为对我来说似乎更合理,因为Streams被懒惰地评估,我没有收集或尝试打印结果.但是在Scala中,即使我没有消耗流,它也会输出一些信息.所以我的问题是导致这种差异的原因是什么?
在我的节目,我多次1 集的Java 8 流,以减少对象的集合到一个单一的一个.在整个执行过程中,此集合的大小可能会有很大差异:从3个对象到数百个.
public void findInterestingFoo(Stream<Foo> foos) {
internalState.update(foos.collect(customCollector()));
}
Run Code Online (Sandbox Code Playgroud)
在优化我的代码和搜索瓶颈的过程中,我在某些时候使流并行.这在当时很有效,因为收藏品都很大.之后,在更改程序的其他部分和参数后,集合变得更小.我意识到不使流并行更有效.这是有道理的:在4个对象的多个线程上分配工作的开销根本不值得.但是对于数百个对象来说它是值得的.
如果我只能使大流并行,那将非常方便:
public void findInterestingFoo(Stream<Foo> foos) {
if (isSmall(foos)) {
internalState.update(foos.collect(customCollector()));
} else {
internalState.update(foos.parallel().collect(customCollector()));
}
}
Run Code Online (Sandbox Code Playgroud)
当然,当从数组,集合或手动创建流时,可以手动执行此操作.也就是说,我们知道流中有哪些元素,因此可以跟踪它.然而,我有兴趣以通用的方式解决这个问题,因此无论传递什么类型的流findInterestingFoo,它都会得到适当的处理和尽可能高效的处理.
count()可能有帮助的东西,除了它在我收集它之前终止流.
我很清楚,流被设计为没有设置大小,特别是:
- 可能是无限的.虽然集合的大小有限,但流不需要.短路操作,例如
limit(n)或findFirst()可以允许无限流上的计算在有限时间内完成.-java.util.stream包装说明
不过,我想知道在对它执行任何操作之前是否有任何方法可以确定流中有多少元素.流是否真的不知道它是从有限集合创建的?
__________
1数千次.在我的情况下,优化这导致总运行时间从大约1.5到0.5秒的加速.
我正在尝试通过(映射)进行分组,然后将值列表转换为不同的列表.
我有DistrictDocuments列表:
List<DistrictDocument> docs = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
然后我在它上面流式传输并按城市分组:
Map<String, List<DistrictDocument>> collect = docs.stream()
.collect(Collectors.groupingBy(DistrictDocument::getCity));
Run Code Online (Sandbox Code Playgroud)
我还有一个方法,它采用了DistrictDocument并从中创建了Slugable:
private Fizz createFizz(DistrictDocument doc) {
return new Fizz().name(doc.getName()).fizz(doc.getFizz());
}
Run Code Online (Sandbox Code Playgroud)
有没有办法将该方法放入我的流中,所以我得到了Map<String, List<Fizz>>?我尝试将第二个参数添加到groupingBy但是找不到合适的方法并且总是遇到编译错误.
编辑:如果我的createFizz返回List<Fizz>怎么办?是否可以选择在Collectors.mapping中平展此列表,因为我仍然想要Map<String, List<Fizz>>而不是Map<String, List<List<Fizz>>>
如何创建Unmodifiable列表/集/映射Collectors.toList/toSet/toMap,因为toList(等)文档为:
返回的List 的类型,可变性,可序列化或线程安全性无法保证
之前的java-10,你必须提供一个Function有Collectors.collectingAndThen,例如:
List<Integer> result = Arrays.asList(1, 2, 3, 4)
.stream()
.collect(Collectors.collectingAndThen(
Collectors.toList(),
x -> Collections.unmodifiableList(x)));
Run Code Online (Sandbox Code Playgroud)