请参阅下面的简单示例,该示例计算列表中每个单词的出现次数:
Stream<String> words = Stream.of("a", "b", "a", "c");
Map<String, Integer> wordsCount = words.collect(toMap(s -> s, s -> 1,
(i, j) -> i + j));
Run Code Online (Sandbox Code Playgroud)
最后,wordsCount是{a=2, b=1, c=1}.
但我的流非常大,我想要并行工作,所以我写道:
Map<String, Integer> wordsCount = words.parallel()
.collect(toMap(s -> s, s -> 1,
(i, j) -> i + j));
Run Code Online (Sandbox Code Playgroud)
但是我注意到这wordsCount很简单HashMap所以我想知道我是否需要明确要求并发映射以确保线程安全:
Map<String, Integer> wordsCount = words.parallel()
.collect(toConcurrentMap(s -> s, s -> 1,
(i, j) -> i + j));
Run Code Online (Sandbox Code Playgroud)
非并发收集器是否可以安全地与并行流一起使用,还是在从并行流收集时只应使用并发版本?
在Java 8中,这适用于:
Stream<Class> stream = Stream.of(ArrayList.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Run Code Online (Sandbox Code Playgroud)
但这不是:
Stream<Class> stream = Stream.of(List.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Run Code Online (Sandbox Code Playgroud)
Maps允许null键,List.class.getSuperclass()返回null.但Collectors.grouping可以在Collectors.java第907行发出NPE:
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
Run Code Online (Sandbox Code Playgroud)
如果我创建自己的收集器,它的工作原理改为:
K key = classifier.apply(t);
Run Code Online (Sandbox Code Playgroud)
我的问题是:
1)Collectors的Javadoc.GroupingBy并没有说它不应该映射一个空键.出于某种原因这种行为是否必要?
2)是否有另一种更简单的方法来接受一个空键,而不必创建我自己的收集器?
所以我希望这个代码能够在新的Java 8日期/时间包下工作,因为它所做的只是将给定的ZonedDateTime转换为字符串并使用相同的内置DateTimeFormatter实例(ISO_INSTANT)返回:
ZonedDateTime now = ZonedDateTime.now();
System.out.println(ZonedDateTime.parse(
now.format(DateTimeFormatter.ISO_INSTANT),
DateTimeFormatter.ISO_INSTANT));
Run Code Online (Sandbox Code Playgroud)
但显然它没有:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2014-09-01T19:37:48.549Z' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {MilliOfSecond=549, NanoOfSecond=549000000, MicroOfSecond=549000, InstantSeconds=1409600268},ISO of type java.time.format.Parsed
at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1918)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1853)
at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)
Run Code Online (Sandbox Code Playgroud)
我已经看过这个条目,但它没有帮助我,因为需要ZonedDateTime对象而不是本地对象,还因为我已经安装了8u20:无法使用Java8中的DateTimeFormatter和ZonedDateTime从TemporalAccessor获取ZonedDateTime
任何人都知道这里发生了什么?
哦,那些棘手的Java 8流与lambdas.它们非常强大,但错综复杂需要一点点围绕它的所有.
假设我有User一个属性类型User.getName().假设我有一个Map<String, User>与名称相关联的用户的地图(例如,登录用户名).让我们进一步说,我有一个比较器的实例UserNameComparator.INSTANCE来排序用户名(可能与花哨的合作者等).
那么如何获取地图中的用户列表,按用户名排序?我可以忽略地图键并执行此操作:
return userMap.values()
.stream()
.sorted((u1, u2) -> {
return UserNameComparator.INSTANCE.compare(u1.getName(), u2.getName());
})
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
但是,我必须提取名称以使用的那一行UserNameComparator.INSTANCE似乎太多的手工工作.有什么方法我可以简单地提供User::getName一些映射函数,只是为了排序,并仍然将User实例返回到收集列表中?
额外奖励:如果我想要排序的东西是两个层次,如User.getProfile().getUsername()?
需要确认一下.以下代码:
CompletableFuture
.supplyAsync(() -> {return doSomethingAndReturnA();})
.thenApply(a -> convertToB(a));
Run Code Online (Sandbox Code Playgroud)
会是这样的:
CompletableFuture
.supplyAsync(() -> {
A a = doSomethingAndReturnA();
convertToB(a);
});
Run Code Online (Sandbox Code Playgroud)
对?
此外,另外两个问题是"我们有什么理由使用thenApply?"
1)有大转换代码?
要么
2)需要在其他地方重用lambda块吗?
我有这个代码:
List<String> strings = Arrays.asList("a", "b", "cc");
for (String s : strings) {
if (s.length() == 2)
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
我想用过滤器和lambda来编写它:
for (String s : strings.stream().filter(s->s.length() == 2)) {
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
我得到Can only iterate over an array or an instance of java.lang.Iterable.
我尝试:
for (String s : strings.stream().filter(s->s.length() == 2).iterator()) {
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
我得到了同样的错误.这甚至可能吗?我真的不想做stream.forEach()并传递消费者.
编辑:对我来说重要的是不要复制元素.
任何Java 8 + JDBC专家都能告诉我以下推理是否有问题吗?而且,如果在神的秘密中,为什么没有这样做?
A java.sql.Date当前是JDBC用于映射到DATE SQL类型的类型,它表示没有时间且没有时区的日期.但是这个类设计得非常好,因为它实际上是一个子类java.util.Date,它可以存储精确的瞬间,最长可达毫秒.
为了在数据库中表示日期2015-09-13,我们因此被迫选择一个时区,在该时区中将字符串"2015-09-13T00:00:00.000"解析为java.util.Date以获得毫秒value,然后java.sql.Date从这个毫秒值构造一个,最后调用setDate()预准备语句,传递一个包含所选时区的Calendar,以便JDBC驱动程序能够从这个毫秒值正确地重新计算日期2015-09-13.通过在任何地方使用默认时区,而不是传递日历,可以使此过程更简单一些.
Java 8引入了一个LocalDate类,它更适合DATE数据库类型,因为它不是精确的时刻,因此不依赖于时区.Java 8还引入了默认方法,这些方法允许对PreparedStatement和ResultSet接口进行向后兼容的更改.
那么,我们还没有错过一个清理JDBC中的混乱的大好机会,同时仍然保持向后兼容性?Java 8可以简单地将这些默认方法添加到PreparedStatement和ResultSet:
default public void setLocalDate(int parameterIndex, LocalDate localDate) {
if (localDate == null) {
setDate(parameterIndex, null);
}
else {
ZoneId utc = ZoneId.of("UTC");
java.util.Date utilDate = java.util.Date.from(localDate.atStartOfDay(utc).toInstant());
Date sqlDate = new Date(utilDate.getTime());
setDate(parameterIndex, sqlDate, Calendar.getInstance(TimeZone.getTimeZone(utc)));
}
}
default LocalDate getLocalDate(int parameterIndex) {
ZoneId utc = ZoneId.of("UTC");
Date sqlDate = getDate(parameterIndex, Calendar.getInstance(TimeZone.getTimeZone(utc)));
if (sqlDate == null) {
return null;
}
java.util.Date utilDate …Run Code Online (Sandbox Code Playgroud) 在Java中,可以轻松地生成无限流Stream.generate(supplier).但是,我需要生成一个最终完成的流.
想象一下,例如,我想要一个目录中所有文件的流.文件数量可能很大,因此我无法预先收集所有数据并从中创建流(via collection.stream()).我需要逐个生成序列.但是流很明显会在某个时刻完成,终端运营商喜欢(collect()或findAny())需要对它进行处理,因此Stream.generate(supplier)不适合这里.
有没有合理的简单方法在Java中执行此操作,而不是自己实现整个Stream接口?
我可以想到一个简单的黑客 - 用无限做它Stream.generate(supplier),并在获取所有实际值时提供null或抛出异常.但是它会破坏标准的流操作符,我只能将它用于我自己的操作符,这些操作符都知道这种行为.
澄清
评论中的人提议我takeWhile()操作员.这不是我的意思.如何更好地表达问题...我不是在问如何过滤(或限制)现有的流,我问如何动态创建(生成)流,而不是先加载所有元素,但是流会有有限的大小(事先未知).
解
我正在寻找的代码是
Iterator it = myCustomIteratorThatGeneratesTheSequence();
StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);
Run Code Online (Sandbox Code Playgroud)
我刚看了一下java.nio.file.Files,该list(path)方法是如何实现的.
我在这里看到很多线程比较并尝试回答哪个更快:newInstance或者new operator.
看看源代码,它看起来newInstance应该慢得多,我的意思是它做了很多安全检查并使用反射.而且我决定先测量一下jdk-8.这是使用的代码jmh.
@BenchmarkMode(value = { Mode.AverageTime, Mode.SingleShotTime })
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class TestNewObject {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(TestNewObject.class.getSimpleName()).build();
new Runner(opt).run();
}
@Fork(1)
@Benchmark
public Something newOperator() {
return new Something();
}
@SuppressWarnings("deprecation")
@Fork(1)
@Benchmark
public Something newInstance() throws InstantiationException, IllegalAccessException {
return Something.class.newInstance(); …Run Code Online (Sandbox Code Playgroud) 考虑以下类层次结构.
class ClassA {
private void hello() {
System.out.println("Hello from A");
}
}
interface Myinterface {
default void hello() {
System.out.println("Hello from Interface");
}
}
class ClassB extends ClassA implements Myinterface {
}
public class Test {
public static void main(String[] args) {
ClassB b = new ClassB();
b.hello();
}
}
Run Code Online (Sandbox Code Playgroud)
运行该程序将出现以下错误:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.testing.ClassA.hello()V from class com.testing.Test
at com.testing.Test.main(Test.java:23)
Run Code Online (Sandbox Code Playgroud)
The inherited method ClassA.hello() cannot hide the public abstract method in …java-8 ×10
java ×9
java-stream ×5
lambda ×2
collectors ×1
concurrency ×1
date ×1
foreach ×1
futuretask ×1
hashmap ×1
java-9 ×1
java-time ×1
jdbc ×1
jmh ×1
performance ×1
sorting ×1