【问题标题】:Understanding iterators了解迭代器
【发布时间】:2021-01-29 03:04:44
【问题描述】:

我正在做一个迭代器的练习,我有 2 个类“菜单”和“菜”菜单。

Class Menu 代表餐厅的菜肴集合。该实现是在一个基本的 ArrayList of Dishes 上完成的。 ArrayList 迭代器用于迭代。

我的疑问是我是否可以在同一个类中使用 for-each 和不同的迭代器以及如何使用。

菜单类:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Menu implements Iterable<Plat> {
    private List<Plat> plats=new ArrayList<Plat>();


    @Override
    public Iterator<Plat> iterator() {
        return new IteratorVegetaria(plats);
    }

    public Iterator<Plat> iteratorCarnivoro() {
        return new IteratorCarnivoro(plats);
    }

    public void afegirPlat(Plat p){
        plats.add(p);
    }

    public static void main(String[] args) {
        Menu m=new Menu();
        Iterator<Plat> c=m.iteratorCarnivoro();
        Iterator<Plat> v=m.iterator();


        m.afegirPlat(new Plat("soup",1.5,true,false,true));
        m.afegirPlat(new Plat("pizza",2.5,true,false,false));
        m.afegirPlat(new Plat("chicken",5.80,false,true,true));
        m.afegirPlat(new Plat("salad",2.5,true,false,true));


        System.out.println("Non-vegetarian menu");
        // Iteration without for-each
        while (c.hasNext()){
            System.out.println(c.next());
        }

        

        // Iteration with for-each (doesn't work and only show vegetarian dishes)
        for(Plat p: m){
            System.out.println(p);
        }


        System.out.println("Vegetarian menu:");

        // Iteration without for-each
        while(v.hasNext()){
            System.out.println(v.next());
        }

        /* Iteration with for-each*/
        for(Plat p: m){
            System.out.println(p);
        }


    }

    public class IteratorVegetaria implements Iterator<Plat>{

        private List<Plat>plats;
        private int actual=0;
        public IteratorVegetaria(List<Plat>p){
            plats = p;
        }

        // With this method we define that has next iterate as long as it finds an object that is vegetarian and adds it to the array.
        @Override
        public boolean hasNext() {
            boolean hiHaNext = false;
            int i = actual;

            while (i<plats.size() && !hiHaNext){
                if (plats.get(i).isVegetaria()) hiHaNext = true;
                else i++;
            }
            return hiHaNext;
        }

        //With this method we define that next will iterate and jump to the next position when it finds a non-vegetarian dish
        @Override
        public Plat next() {
            Plat p=plats.get(actual++);
            while (!p.isVegetaria()){
                p=plats.get(actual++);
            }

            return p;
        }
    }

    public class IteratorCarnivoro implements Iterator<Plat>{

        private List<Plat>plats;
        private int actual=0;
        public IteratorCarnivoro(List<Plat>p){
            plats = p;
        }

        // With this method we define that has next iterate as long as it finds an object that is non-vegetarian and adds it to the array.
        @Override
        public boolean hasNext() {
            boolean hiHaNext = false;
            int i = actual;

            while (i<plats.size() && !hiHaNext){
                if (!plats.get(i).isVegetaria()) hiHaNext = true;
                else i++;
            }
            return hiHaNext;
        }

        //With this method we define that next will iterate and jump to the next position when it finds a vegetarian dish
        @Override
        public Plat next() {
            Plat p=plats.get(actual++);
            while (p.isVegetaria()){
                p=plats.get(actual++);
            }

            return p;
        }
    }


} 

菜品类:

public class Plat {
    private String nom;
    private double preu;
    private boolean vegetaria;
    private boolean apteCeliacs;
    private boolean baixCalories;

    public Plat(String nom, double preu, boolean vegetaria, boolean apteCeliacs, boolean baixCalories) {
        this.nom = nom;
        this.preu = preu;
        this.vegetaria = vegetaria;
        this.apteCeliacs = apteCeliacs;
        this.baixCalories = baixCalories;
    }


    public boolean isVegetaria() {
        return vegetaria;
    }

    @Override
    public String toString() {
        String missatge = "Plat{" +
                "nom='" + nom + '\'' +
                ", preu=" + preu +
                ", apteCeliacs=" + apteCeliacs +
                ", baixCalories=" + baixCalories +
                ", vegetaria=";

        if (isVegetaria()){
            return missatge+" es vegetaria";
        }else{
            return missatge+" no es vegetaria";
        }

    }
}

所以基本上当我运行代码时,它会显示:

Non-vegetarian menu

Plat{nom='chicken', preu=5.8, apteCeliacs=true, baixCalories=true, vegetaria= no es vegetaria

Plat{nom='soup', preu=1.5, apteCeliacs=false, baixCalories=true, vegetaria= es vegetaria
Plat{nom='pizza', preu=2.5, apteCeliacs=false, baixCalories=false, vegetaria= es vegetaria
Plat{nom='salad', preu=2.5, apteCeliacs=false, baixCalories=true, vegetaria= es vegetaria

Vegetarian menu:


Plat{nom='soup', preu=1.5, apteCeliacs=false, baixCalories=true, vegetaria= es vegetaria
Plat{nom='pizza', preu=2.5, apteCeliacs=false, baixCalories=false, vegetaria= es vegetaria
Plat{nom='salad', preu=2.5, apteCeliacs=false, baixCalories=true, vegetaria= es vegetaria


Plat{nom='soup', preu=1.5, apteCeliacs=false, baixCalories=true, vegetaria= es vegetaria
Plat{nom='pizza', preu=2.5, apteCeliacs=false, baixCalories=false, vegetaria= es vegetaria
Plat{nom='salad', preu=2.5, apteCeliacs=false, baixCalories=true, vegetaria= es vegetaria

【问题讨论】:

  • 就像阅读代码时的旁白一样,c、m 和 v 等变量名称非常难以描述,使您的代码更难阅读。考虑使用完整的单词和短语而不是单个字母。

标签: java oop iteration iterable


【解决方案1】:

如果这是学校的案例研究,它成功地说明了如何为实现 Iterable 的类创建多个迭代器是一个坏主意 :) 我并不是说这是不可能的,只是说这是不可取的。

如果您想在迭代时更改集合,通常会使用迭代器

Iterator.remove();

如果您尝试在使用 Iterator/ListIterator 以外的任何东西循环遍历集合时删除元素,您将炸毁我们都非常喜欢的 ConcurrentModificationException

您应该利用 Java 8 中引入的 Streams(除非出于某种原因您使用的是旧版本)

List<Plate> menu = new ArrayList();
            
List<Plate> vegetarianChoices = menu.stream().filter(new Predicate<Plate>() {
                @Override
                public boolean test(Plate plate) {
                    return plate.isVegitarian();
                }
            }).collect(Collectors.toList());

List<Plate> nonVegetarianChoices= menu.stream().filter(new Predicate<Plate>() {
                    @Override
                    public boolean test(Plate plate) {
                        return !plate.isVegitarian();
                    }
                }).collect(Collectors.toList());

【讨论】:

  • 我明白了,所以我不应该使用迭代器,除非我想从集合中删除一些元素??我认为他们希望我们学习的是迭代器如何在内部使用我们自己的,因为我们已经开始使用 Java OOP 及其方法和库
  • 是的,从 java 8+ 开始,我不建议在更新循环之外的任何地方使用迭代器,在这些更新循环中需要减少集合,同时仍在循环中。现在你正在使用迭代器作为过滤器,这不是它们的用途。
【解决方案2】:

这个 while 循环似乎坏了。循环结构本身有点奇怪且难以阅读,但问题似乎是您似乎也从未更新actual。

        while (i<plats.size() && !hiHaNext){
            if (plats.get(i).isVegetaria()) hiHaNext = true;
            else i++;
        }
        return hiHaNext;

尝试类似:

        while (i<plats.size()){
            if (plats.get(i).isVegetaria()) hiHaNext = true;
            else i++;
        }
        actual = i;
        return hiHaNext;

【讨论】:

  • 我改了,现在运行代码没有提示
  • 另外,在 while 循环中,我只是将变量“i”更改为“实际”,感谢您告诉我!
猜你喜欢
  • 2016-04-18
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 2010-12-24
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多