4

Java レコード、プレビュー機能を学習していますが、以下のコードを実行すると StackOverflow 例外が発生します。

    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    public class Example {
        public record Course(String name, Student topper) { }
        public record Student(String name, List<Course> enrolled) {}

        public static void main(String[] args) {
            Student john = new Student("John", new ArrayList<>());
            john.enrolled().add(new Course("Enrolled for Math", john));
            john.enrolled().add(new Course("Enrolled for History", john));
            System.out.println(john);
        }
    }


Below is the exception trace :


 java --enable-preview Example
 Exception in thread "main" java.lang.StackOverflowError
    at Example$Course.toString(Example.java:6)
    at java.base/java.lang.String.valueOf(String.java:3388)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:167)
    at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)

例外から、それが toString() に関係していることがわかり、以下のコードのようにレコードで toString() をオーバーライドすると、 Exception が表示されません。

// code with implementation of toString()
public class Example {

    public record Course(String name, Student topper) {
    public String toString()
        {
            return name;
        }
   }
   public record Student(String name, List<Course> enrolled) {
   public String toString()
        {
             return this.name+" : "+enrolled.stream().map(s->s.toString()).collect(Collectors.joining(","));
        }
   }
   public static void main(String... args) {
       Student john = new Student("John", new ArrayList<>());
       john.enrolled().add(new Course("Enrolled for Math", john));
       john.enrolled().add(new Course("Enrolled for History", john));
       System.out.println(john);
   }
}

このコードは John : Enrolled for Math,Enrolled for History を出力します。toString() をオーバーライドしないと StackOverflow が発生する理由を誰かが説明してもらえますか? また、印刷するとStackOverflowが表示されますjohn.hashCode()

4

4 に答える 4

2

特に関係ありませんRecord#toString。宣言を詳しく見てみましょう。

public record Course(String name, Student topper) {}
public record Student(String name, List<Course> enrolled) {}

Course#toStringニーズStudent#toStringStudent#toStringニーズCourse#toString。そのため、印刷しようとするとStudent、登録されているすべてCourseが一緒に印刷されます。それらはCourse必要なStudentので、Student内部に印刷されます。このループは、例外が発生するまで続きますStackOverflow

この種のシナリオを回避するには、相互に依存しないようにコードを再配置する必要があります。インスタンスごとに ID を作成できます。例は次のとおりです。

public record Course(String name, String studentId) {}
public record Student(String name, String studentId, List<Course> courses) {}
于 2020-06-02T08:57:13.713 に答える