【问题标题】:Solve Java heap space error when adding new values to double Arraylist解决双 Arraylist 添加新值时 Java 堆空间错误
【发布时间】:2020-03-29 19:14:04
【问题描述】:

上下文

我有一项任务要求我从文本文件中读取食谱并操作测量单位和成分数量等内容。我已经设法将配方分成三个数组列表,现在必须开始将英制单位转换为公制。但是当我尝试乘以和转换相应的单位时,我得到了 Java 堆空间错误。我在网上查看了如何解决此问题,并意识到这可能与数组列表泄漏内存或使用过多空间有关。问题是我不知道这可能发生在哪里,并且已经尝试使用浮点列表或整数列表而不是双精度,但它仍然没有工作,因为我仍然需要使用小数。我知道字符串转换为 ml 有效,但不知道相应的数字转换是否有效,任何帮助将不胜感激。

代码

import java.util.*;
import java.io.*;
class Main {
    /**
     * Prints methods to user
     */
    public static void main(String[] args) throws Exception{
        servingReader();
        System.out.println(sSize);
        ingrReader();
        System.out.println(ingrList);
        ingrSeperator();
        System.out.println(ingrSeperatorList);
        System.out.println(ingrSeperatorList.get(7));
        divide();
        System.out.println(ingrSeperatorList);
        converter();
        System.out.println(ingrList);
        System.out.print(ingrSeperatorList);
        multiply();
        System.out.print(ingrSeperatorList);
    }//end main

    static int sSize;//int for serving size

    /**
     * Reads text file
     */
    public static void servingReader() throws Exception{

        //recipe read
        File recipe = new File("/home/runner/recipe.txt");
        Scanner sc = new Scanner(recipe);

        //loop to find serving size
        while(sc.hasNextLine()){
            String s = sc.nextLine().toUpperCase();
            if(s.equals("SERVING SIZE")){
                sSize = sc.nextInt();
            }
        }

        sc.close();//scanner closed
    }//servingReader

    static ArrayList<String> ingrList = new ArrayList<>();//ArrayList for ingredients created

    static String scan;

    /**
     * Reads recipe and adds ingredients section to list
     */
    public static void ingrReader() throws Exception{

        //recipe read
        File recipe = new File("/home/runner/recipe.txt");
        Scanner sc = new Scanner(recipe);

        //loop to find ingredients section or recipe
        while(sc.hasNextLine()){
            String s = sc.nextLine().toUpperCase();
            //if scanner finds header INGREDIENTS, section added to ingrList
            if(s.equals("INGREDIENTS")){
                while(sc.hasNextLine()){
                    int i = 0;
                    scan = sc.nextLine();
                    ingrList.add(i, scan);
                    i+= 1;
                    //if nothing is found, breaks
                    if(scan.equals("")){
                        break;
                    }
                }
            }
        }
        sc.close();//scanner closed

        Collections.reverse(ingrList);//reverse method reverses order of elements in ingrList

        int ingr1 = ingrList.size() - 1;
        ingrList.remove(ingr1);

    }//ingrReader

    static ArrayList<Float> ingrSeperatorList = new ArrayList<Float>();//ArrayList for seperated ingredients created

    /**
     * Seperates ingredient quantitys from ingredints list and adds to seperated list
     */
    public static void ingrSeperator(){

        float ingr2 = 0;

        for(int i = 0; i <ingrList.size(); i++){
            String split [] = ingrList.get(i).split(" ");
            ingr2 =  Float.parseFloat(split[0]);
            ingrSeperatorList.add(ingr2);

        }
    }//end ingrSeperator


    /**
     * Gets serving size input from user and then adjusts seperated ingredinets accordingly
     */
    public static void divide() throws Exception{
        Scanner sc = new Scanner(System.in);

        System.out.print("Enter your serving size: ");//serving size enetered
        int servingSize = sc.nextInt();

        for(int i=0;i<ingrSeperatorList.size();i++){
            ingrSeperatorList.set(i,ingrSeperatorList.get(i)*servingSize);//origanal quantiys multiplyed by new serving size
        }

        for(int i=0;i<ingrSeperatorList.size();i++){
            ingrSeperatorList.set(i,ingrSeperatorList.get(i)/4);//multiplyed quantitys now didvided by origanal serving size 4
        }
        sc.close();//scanner closed
    }//end divide

问题始于我的转换器方法:

    /**
     * Asks user for choice of units and converts arraylists accorrdingly
     */
    public static void converter() throws Exception{
        Scanner sc = new Scanner(System.in);
/*
        System.out.print("Use imperial or metric: ");//asks user for imperial or metric
        char choice =  sc.next().charAt(0);

        //if user chooses metric
        if((choice == 'a') || (choice == 'A')){*/

        //convert tbsp to ml
        for(int i = 0; i < ingrList .size(); i++){
            //if ingrList contains tbsp replaced with ml
            if(ingrList.get(i).contains("tbsp")){
                ingrList.set(i,ingrList.get(i).replace("tbsp", "ml"));

                for(int j=0;j<ingrSeperatorList.size();j++){
                    ingrSeperatorList.add(ingrSeperatorList.get(j)*15);

                }
            }
        }

        //convert tbsp to ml
        for(int i = 0; i < ingrList .size(); i++){
            //if ingrList contains cup replaced with ml
            if(ingrList.get(i).contains("cup")){
                ingrList.set(i,ingrList.get(i).replace("cup", "ml"));

                for(int j=0;j<ingrSeperatorList.size();j++){
                    ingrSeperatorList.set(j,ingrSeperatorList.get(j)*250);
                }
            }
        }

        //convert tsp to ml
        for(int i = 0; i < ingrList .size(); i++){
            //if ingrList contains tsp replaced with ml
            if(ingrList.get(i).contains("tsp")){
                ingrList.set(i,ingrList.get(i).replace("tsp", "ml"));

                for(int j=0;j<ingrSeperatorList.size();j++){
                    ingrSeperatorList.set(j,ingrSeperatorList.get(j)*5);
                }
            }
        }

    //}
    }//end converter

    /**
     * Gets serving size input from user and then adjusts seperated ingredinets accordingly
     */
    public static void multiply() throws Exception{

        for(int j=0;j<ingrSeperatorList.size();j++){
            ingrSeperatorList.set(j,ingrSeperatorList.get(j)*250);
        }
    }//end divide
}//end main

【问题讨论】:

  • 与您的问题无关,但观察和建议:您的代码不是面向对象的。对于这样的作业,我希望看到像RecipeIngredientUnits 这样的课程共同解决问题。如果您可以分离职责,它将使您的代码更易于阅读和理解。如果您无法做到这一点,我建议您为变量使用更清晰的名称,例如ingrList -&gt; ingredientssc -&gt; scanneringrSeparatorList -&gt; quantities。当您可以轻松阅读代码时,您会发现调试起来会容易得多。
  • 感谢您的反馈。在我的下一个任务中,我肯定会考虑到这一点,因为我现在意识到调试这么多事情是一件很痛苦的事情。

标签: java arraylist memory-management file-io memory-leaks


【解决方案1】:

问题出在这里,当从汤匙转换为毫升时:

for(int j=0;j<ingrSeperatorList.size();j++){
    ingrSeperatorList.add(ingrSeperatorList.get(j)*15);

}

请注意,在其他所有转换中,您都使用ingr.SeperatorList.set,而不是.add.add 使您的列表变得更大。您在循环列表时使用了.add,因此无论何时使用.add,列表都会变大,您将永远无法逃脱循环(也就是说,直到空间用完)。

【讨论】:

  • 非常感谢您的回复和解决方案,现在终于可以使用了。但是,我现在遇到的问题是我需要合并成分数量的数组列表和成分及其单位的列表。我该怎么做呢,我要创建另一个数组列表并添加两者吗?
  • 真的取决于你想怎么做。我建议创建一个 Ingredient 类,其中包含一个 String 表示成分名称或类型,以及一个 int 表示数量。然后遍历您的数量列表和名称列表,创建一个新的Ingredient 对象来表示您已有的信息,并将其添加到ArrayList&lt;Ingredient&gt;。您可能还想存储有关它所指单位的一些信息。另一种方法是将数量和名称存储在同一个 String 中,但这会使单位转换和其他事情变得非常混乱。
  • 再次感谢您的反馈。我已经通过创建一个新类并尝试使用字符串和 int 来尝试您的第一个解决方案,但是通过循环两个列表并将它们添加到新列表成分中,我无法走得更远。您还有其他可能有帮助的提示吗?
  • 好吧,名称列表和数量列表可能具有相同的长度,但为了安全起见,将两个长度中的最小值存储在变量length 中,然后执行类似这样的操作(伪-code):for (int i = 0; i &lt; length; i++) { ingredients.add(new Ingredient(nameList.get(i), quantityList.get(i)); },其中的成分是您的成分列表,其中(可选)成分的构造函数接受一个字符串和一个数量。
  • 这是我到目前为止的代码,但它仍然无法正常工作: public static void Ingredients() throws Exception{ int length = IngredientList.size();字符串 s;整数数量; for (int i = 0; i
猜你喜欢
  • 2012-03-20
  • 2015-01-23
  • 2012-11-14
  • 2011-11-05
  • 1970-01-01
  • 2021-11-28
  • 2012-03-26
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多