java - Iterable 接口(interface)中的歧义及其在 Java 中的实现

标签 java hadoop mapreduce java-stream iterable

是否使用 Java Iterator接口(interface)强制我们在调用 next() 时返回一个新对象这个接口(interface)上的方法?我浏览了文档,每次调用都没有返回一个新对象的义务,但这会导致很多歧义。看来,Hadoop mapreduce 框架打破了一些未记录的规则,这在我的简单程序中导致了许多问题(包括使用 Java8 Streams)。当我调用 next() 时,它返回具有不同内容的相同对象Iterator 上的方法(虽然违背了我的想象,但似乎并没有违反 Iterator 的规则,至少似乎没有违反 Iterator 接口(interface)的记录规则)。我想知道为什么会这样?是mapreduce错误吗?还是没有记录 Iterator 是 Java 的错误?每次调用 next() 时返回新实例的接口(interface)方法:
为了简单起见并显示 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}]
更糟糕的是,想象一下当我们使用 Streams 醒来时会发生什么。在 java 。 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}
作为用户,我想按原样使用接口(interface),并且不关心该接口(interface)的实现。
问题是这里我知道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 的未注释常规规则是否是 mapreduce 错误?和 Iterator (或者有我没有注意到的这种行为的文档)?
  • 还是 Java 没有记录 IterableIterator在每次调用时返回新对象的接口(interface)?
  • 还是我作为程序员的错?
  • 最佳答案

    为 Iterable 返回具有不同内容的相同可变对象是非常不寻常的。我在 java 语言引用中没有找到任何东西;虽然搜索不多。这很简单,也容易出错,无法正确使用语言。
    您提到其他工具,例如 Streams,是恰当的。
    此外,下一个 java 的记录类型仅适用于类似元组的用法,当然是多个不可变对象(immutable对象)。 “您的”Iterable 无法在集合中使用,除非在 .next().clone() 上使用之类的。
    Iterable 的这个弱点与将可变对象作为 Map 键属于同一类。这是致命的错误。

    关于java - Iterable 接口(interface)中的歧义及其在 Java 中的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62927701/

    相关文章:

    hadoop - 从故障中恢复后的DataNode

    java - 在查询错误中将不同的数据类型插入postgreSQL

    java - hadoop 中多种输入格式作为单一输入格式

    java - 尝试使用 Spring Boot 项目在 Java 17 中与本地 MYSQL 数据库建立 JDBC 连接时出错

    hadoop - Google Cloud Dataproc - Spark 和 Hadoop 版本

    hadoop - 如何在 oozie 作业中指定多个 libpath?

    Python - 如何将目录作为 MapReduce 输入传递

    java - 如何在 HADOOP 运行时生成多个文件名?

    java - 扩展 Java 语法(卫生宏)的最简单方法是什么

    java - 在 JPA 中映射复杂的 Map