【发布时间】:2020-11-05 17:01:23
【问题描述】:
当我们在这个接口上调用next() 方法时,Java Iterator 接口是否强制我们返回一个新对象?我浏览了文档,每次调用都没有返回一个新对象的义务,但这会导致很多歧义。看来,Hadoop mapreduce 框架打破了一些未记录的规则,这在我的简单程序中导致了许多问题(包括使用 Java8 Streams)。当我在Iterator上调用next()方法时,它返回的是相同的Object,但内容不同(虽然和我的想象不符,但似乎并没有打破Iterator的规则,至少看起来并没有打破Iterator接口的记录规则)。我想知道为什么会这样?是mapreduce错误吗?还是 Java 错误没有记录 Iterator 接口以在每次调用 next() 方法时返回新实例:
为了简单起见并显示 hadoop mapreduce 中发生的情况,我编写了自己的 Iterator,这与 mapreduce 所做的类似,因此您可以理解我的意思(所以它不是一个完美的程序,并且可能有很多问题,但请专注于我试图展示的概念)。
想象一下我有以下Hospital 实体:
@Getter
@Setter
@AllArgsConstructor
@ToString
public class Hospital {
private AREA area;
private int patients;
public Hospital(AREA area, int patients) {
this.area = area;
this.patients = patients;
}
public Hospital() {
}
}
为此我写了以下MyCustomHospitalIterable:
public class MyCustomHospitalIterable implements Iterable<Hospital> {
private List<Hospital> internalList;
private CustomHospitalIteration customIteration = new CustomHospitalIteration();
public MyCustomHospitalIterable(List<Hospital> internalList) {
this.internalList = internalList;
}
@Override
public Iterator<Hospital> iterator() {
return customIteration;
}
public class CustomHospitalIteration implements Iterator<Hospital> {
private int currentIndex = 0;
private Hospital currentHospital = new Hospital();
@Override
public boolean hasNext() {
if (MyCustomHospitalIterable.this.internalList.size() - 1 > currentIndex) {
currentIndex++;
return true;
}
return false;
}
@Override
public Hospital next() {
Hospital hospital =
MyCustomHospitalIterable.this.internalList.get(currentIndex);
currentHospital.setArea(hospital.getArea());
currentHospital.setPatients(hospital.getPatients());
return currentHospital;
}
}
}
在这里,我不是在 next() 方法调用上返回新对象,而是返回具有不同内容的相同对象。你可能会问这样做有什么好处?它在 mapreduce 中具有自己的优势,因为在大数据中,出于性能考虑,他们不想创建新对象。这是否违反了Iterator 接口的任何记录规则?
现在让我们看看以这种方式实现Iterable 的一些后果:
考虑以下简单程序:
public static void main(String[] args) {
List<Hospital> hospitalArray = Arrays.asList(
new Hospital(AREA.AREA1, 10),
new Hospital(AREA.AREA2, 20),
new Hospital(AREA.AREA3, 30),
new Hospital(AREA.AREA1, 40));
MyCustomHospitalIterable hospitalIterable = new MyCustomHospitalIterable(hospitalArray);
List<Hospital> hospitalList = new LinkedList<>();
Iterator<Hospital> hospitalIter = hospitalIterable.iterator();
while (hospitalIter.hasNext()) {
Hospital hospital = hospitalIter.next();
System.out.println(hospital);
hospitalList.add(hospital);
}
System.out.println("---------------------");
System.out.println(hospitalList);
}
程序的输出如下所示,非常不合逻辑和违反直觉:
Hospital{area=AREA2, patients=20}
Hospital{area=AREA3, patients=30}
Hospital{area=AREA1, patients=40}
---------------------
[Hospital{area=AREA1, patients=40}, Hospital{area=AREA1, patients=40}, Hospital{area=AREA1, patients=40}]
更糟糕的是,想象一下当我们在 Java 中使用 Streams 工作时会发生什么。以下程序在 Java 中的输出是什么:
public static void main(String[] args) {
List<Hospital> hospitalArray = Arrays.asList(
new Hospital(AREA.AREA1, 10),
new Hospital(AREA.AREA2, 20),
new Hospital(AREA.AREA3, 30),
new Hospital(AREA.AREA1, 40));
MyCustomHospitalIterable hospitalIterable = new MyCustomHospitalIterable(hospitalArray);
Map<AREA, Integer> sortedHospital =
StreamSupport.stream(hospitalIterable.spliterator(), false)
.collect(Collectors.groupingBy(
Hospital::getArea, Collectors.summingInt(Hospital::getPatients)));
System.out.println(sortedHospital);
}
这取决于我们使用并行流还是顺序流: 在seqentioal中,一个输出如下:
{AREA2=20, AREA1=40, AREA3=30}
同时它是:
{AREA1=120}
作为用户,我想按原样使用接口,并且不关心该接口的实现。
问题是,在这里我知道MyCustomHospitalIterable 是如何实现的,但是在hadoop mapreduce 中我必须实现像下面这样的方法,我不知道Iterable<IntWritable> 来自哪里以及它的实现是什么。我只想将它用作纯 Iterable 接口,但正如我在上面显示的那样,它不能按预期工作:
public void reduce(Text key, Iterable<IntWritable> values, Context context
) throws IOException, InterruptedException {
List<IntWritable> list = new LinkedList<>();
Iterator<IntWritable> iter = values.iterator();
while (iter.hasNext()) {
IntWritable count = iter.next();
System.out.println(count);
list.add(count);
}
System.out.println("---------------------");
System.out.println(list);
}
这是我的问题: 为什么我的简单程序坏了?
- 不执行
Iterable和Iterator的未注释常规规则是否是 mapreduce 错误(或者我没有注意到此行为的文档)? - 还是 Java 没有记录
Iterable和Iterator接口以在每次调用时返回新对象? - 还是我作为程序员的错?
【问题讨论】:
-
拜托,下次你问问题时,请多注意语法和拼写。
-
我希望你能接受我的道歉@GiorgiTsiklauri
标签: java hadoop mapreduce java-stream iterable