这个问题不是关于众所周知和记录的事实,HashMap它不是线程安全的,而是关于它在HotSpot和JDK代码上的特定故障模式.我很惊讶这个代码在NPE中失败了:
public static void main(String[] args) {
Map<Integer, Integer> m = new HashMap<>(0, 0.75f);
IntStream.range(0, 5).parallel().peek(i -> m.put(i, i)).map(m::get).count();
}
Run Code Online (Sandbox Code Playgroud)
NPE的来源并不神秘:.map(m::get)尝试拆箱时的步骤null.它在5次运行中大约有4次失败.
在我的机器上Runtime#availableProcessors()报告8,所以假设长度为5的范围被分成5个子任务,每个子任务只有一个成员.我还假设我的代码以解释模式运行.它可能正在调用JIT编译HashMap或Stream方法,但是顶层被解释,因此排除了将HashMap状态加载到线程本地存储器(寄存器/堆栈)中的任何变化,从而延迟了另一个线程对更新的观察.如果五个put操作中的某些操作在同一时间不在不同的核心上执行,我不认为它会破坏HashMap内部结构.鉴于工作量很小,个别任务的时间安排必须非常精确.
它是否真的是精确的时间(commonPool必须取消停放的线程),还是有其他途径导致Oracle/OpenJDK HotSpot失败?我目前的版本是
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
Run Code Online (Sandbox Code Playgroud)
更新:我发现即使只进行两次插入也有类似的高故障率:
IntStream.range(0, 2).parallel().peek(i -> m.put(i, i)).map(m::get).count();
Run Code Online (Sandbox Code Playgroud) 从char数组,我想构建一个流来使用java 8功能,如过滤器和地图.
char[] list = {'a','c','e'};
Stream<Character> cStream = Stream.of(list);
// Stream<Character> cStream = Arrays.stream(list);
Run Code Online (Sandbox Code Playgroud)
第一种方法不起作用(原因:将cStream更改为Stream<char[]>).注释行也不起作用(原因:stream(T[])类型数组中的方法不适用于arguments(char[])).
我知道如果char[] list更改为int[],一切正常使用IntStream.但我不希望每次转换char[]到int[]每个时间或更改到一个列表中,当我需要在使用流库char阵列.
流中是否有sum()等效方法,可以执行流中给出的值的乘法?
我有一个像这样的整数列表:
List<Integer> listOfIntegers = new ArrayList<>();
listOfIntegers.addAll(Arrays.asList(1,4,2,7,5));
Run Code Online (Sandbox Code Playgroud)
我能够得到所有整数的总和,但无法找到可以乘以值并给出输出的API.
listOfIntegers.stream().mapToInt(a -> a).sum();
Run Code Online (Sandbox Code Playgroud)
如果我尝试使用forEach来执行此操作,那么我无法存储结果,因为只允许在其中使用最终变量.
有没有替代方案?
我Fruit在arraylist中有一个对象列表,我想将fruitName修改为其复数名称.参考示例:
@Data
@AllArgsConstructor
@ToString
class Fruit {
long id;
String name;
String country;
}
List<Fruit> fruits = Lists.newArrayList();
fruits.add(new Fruit(1L, "Apple", "India"));
fruits.add(new Fruit(2L, "Pineapple", "India"));
fruits.add(new Fruit(3L, "Kiwi", "New Zealand"));
Comparator<Option> byNameComparator = (e1, e2) -> e1.getName().compareToIgnoreCase(e2.getName());
fruits = fruits.stream().filter(fruit -> "India".equals(fruit.getCountry()))
.sorted(byNameComparator).collect(Collectors.toList());
List<Fruit> fruitsWithPluralNames = Lists.newArrayList();
for (Fruit fruit : fruits) {
fruit.setName(fruit.getName() + "s");
fruitsWithPluralNames.add(fruit);
}
System.out.println(fruitsWithPluralNames);
// which prints [Fruit(id=1, name=Apples, country=India), Fruit(id=2, name=Pineapples, country=India), Fruit(id=3, name=Kiwis, country=New Zealand)]
Run Code Online (Sandbox Code Playgroud)
我们有没有办法使用java8流实现相同的行为?
这是来自Oracle的JDK 8实现的Stream接口:
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> sorted();
}
Run Code Online (Sandbox Code Playgroud)
并且很容易在运行时将其清除,并且在编译时不会生成警告.这是一个例子:
class Foo {
public static void main(String[] args) {
Arrays.asList(new Foo(), new Foo()).stream().sorted().forEach(f -> {});
}
}
Run Code Online (Sandbox Code Playgroud)
这将编译得很好,但会在运行时抛出异常:
Exception in thread "main" java.lang.ClassCastException: Foo cannot be cast to java.lang.Comparable
Run Code Online (Sandbox Code Playgroud)
sorted在编译器实际可以捕获这些问题的地方没有定义该方法的原因是什么?也许我错了,但不是这么简单:
interface Stream<T> {
<C extends Comparable<T>> void sorted(C c);
}
Run Code Online (Sandbox Code Playgroud)
?
显然,那些实现这一点的人(考虑到编程和工程方面比我早了几年)必须有一个很好的理由,我无法看到,但这是什么原因?
我有一个Foo包含这些字段的课程:
id:int/name; String/targetCost:BigDecimal/actualCost:BigDecimal
我得到了这个类的对象的arraylist.例如:
new Foo(1, "P1", 300, 400),
new Foo(2, "P2", 600, 400),
new Foo(3, "P3", 30, 20),
new Foo(3, "P3", 70, 20),
new Foo(1, "P1", 360, 40),
new Foo(4, "P4", 320, 200),
new Foo(4, "P4", 500, 900)
Run Code Online (Sandbox Code Playgroud)
我想通过创建"targetCost"和"actualCost"的总和并将"行"分组来转换这些值,例如
new Foo(1, "P1", 660, 440),
new Foo(2, "P2", 600, 400),
new Foo(3, "P3", 100, 40),
new Foo(4, "P4", 820, 1100)
Run Code Online (Sandbox Code Playgroud)
我现在写的:
data.stream()
.???
.collect(Collectors.groupingBy(PlannedProjectPOJO::getId));
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
假设有一个名为Type的简单枚举,如下所示:
enum Type{
X("S1"),
Y("S2");
private String s;
private Type(String s) {
this.s = s;
}
}
Run Code Online (Sandbox Code Playgroud)
s使用for-loop的静态方法(假设该方法在enum中定义)可以轻松地找到给定的正确枚举,例如:
private static Type find(String val) {
for (Type e : Type.values()) {
if (e.s.equals(val))
return e;
}
throw new IllegalStateException(String.format("Unsupported type %s.", val));
}
Run Code Online (Sandbox Code Playgroud)
我认为使用Stream API表达的功能等价物将是这样的:
private static Type find(String val) {
return Arrays.stream(Type.values())
.filter(e -> e.s.equals(val))
.reduce((t1, t2) -> t1)
.orElseThrow(() -> {throw new IllegalStateException(String.format("Unsupported type %s.", val));});
}
Run Code Online (Sandbox Code Playgroud)
我们怎么能写得更好更简单?这段代码感觉很强烈,不太清楚.该reduce()特别是似乎笨重和滥用,因为它没有任何积累,不进行计算,并始终直接返回t1(所提供的过滤器返回一个值-如果没有这显然是一个灾难),更何况t2是有多余的混乱.然而,我在Stream API中找不到任何东西,只是以某种方式T从a 直接返回a …
我想要一个与流相当的:
public static <T extends Number> T getSum(final Map<String, T> data) {
T sum = 0;
for (String key: data.keySet())
sum += data.get(key);
return sum;
}
Run Code Online (Sandbox Code Playgroud)
这段代码实际上并没有编译,因为0不能分配给类型T,但你明白了.
我想重构我在一些代码中使用流的方式.第一个例子是我目前是如何做到的.第二个例子就是我试图让它看起来像.
Set<String> results = new HashSet<String>();
someDao.findByType(type)
.stream()
.forEach(t-> result.add(t.getSomeMethodValue()) );
Run Code Online (Sandbox Code Playgroud)
它看起来像这样吗?如果是这样我该怎么做呢?
Set<String> results = someDao.findByType(type)
.stream()
.collect( /* ?? no sure what to put here */ );
Run Code Online (Sandbox Code Playgroud) java-8 ×10
java-stream ×10
java ×9
lambda ×2
boxing ×1
byte ×1
collections ×1
comparable ×1
enums ×1
generics ×1