这个设计中导致无限循环的错误是什么?

时间:2017-09-14 11:57:59

标签: java recursion stack-overflow infinite-loop

我将通过给你一个描述性的例子来解释自己。让我们说我编写了一个非常简单的云存储模拟,一个简单的终端程序。我有两个主要类,用户和文件编码如下:

class User {
       Set<File> sharedFiles;
       void shareFile(File f){
           sharedFiles.add(f);
           f.shareWith(this);
       }
}

class File {
       Set<User> sharedUsers;
       void shareWith(User u){
           sharedUsers.add(u);
           u.shareFile(this);
       }
}

我假装有权访问已分享给用户的文件以及已共享文件的用户,因此我对列表sharedFilessharedUsers进行了编码。

然后,我这样做:

main(){
    User u = new User();
    File f = new File();
    u.shareFile(f); // or f.shareWith(u), doesn't matter
}

我知道这是一个非常明显的无限循环案例。实际上,此代码会导致Exception in thread "main" java.lang.StackOverflowError。两种方法都无限期地相互呼叫。

那么,在您看来,对于这个问题,理想的解决方案是什么,这两个类的好设计是什么?

5 个答案:

答案 0 :(得分:3)

在调用class User { Set<File> sharedFiles; boolean hasFile (File f) { return sharedFiles.contains(f); } void shareFile(File f){ sharedFiles.add(f); if (!f.hasUser(this)) f.shareWith(this); } } class File { Set<User> sharedUsers; boolean hasUser (User u) { return sharedUsers.contains(u); } void shareWith(User u){ sharedUsers.add(u); if (!u.hasFile(this)) u.shareFile(this); } } 方法之前,您可以添加检查一个类的对象是否已经拥有对另一个类的对象的引用:

sharedUsers

编辑:当然这段代码缺少sharedFilesdeclare @Questions varchar(100)= '"001122;Sale Item 1", "001123;Sale Item 23", "001124;Sale Item 24"' DECLARE @myXML AS XML = N'<H><r>' +Replace(@Questions, ',', '</r><r>') + '</r></H>' select @myXML ;WITH cte AS ( SELECT CAST(N'<H><r>' + Replace(Vals.id.value('.', 'NVARCHAR(50)') ,';' , '</r><r>') + '</r></H>' as XML) AS val FROM @myXML.nodes('/H/r') AS Vals(id) ) ,mycte1 as ( SELECT distinct Replace( S.a.value('(/H/r)[1]', 'NVARCHAR(50)') , '"', '') AS c1, Replace( S.a.value('(/H/r)[2]', 'NVARCHAR(50)') , '"', '') AS c2 FROM cte CROSS APPLY val.nodes('/H/r') S(a) ) select * from mycte1 集的初始化,但我假设您在实际代码中进行了初始化。

答案 1 :(得分:0)

你正在打电话,在“这个”上继续称你的方法无限时间

class File {
   Set<User> sharedUsers;
   void shareWith(User u){
       sharedUsers.add(u);
       u.shareFile(this);
   }
}

答案 2 :(得分:0)

2个函数(shareFile和shareWith)只是一次又一次地调用eacher。您需要添加一些检查,无论该集合是否已包含该元素并返回,或者执行类似的操作......

class User {
   Set<File> sharedFiles;
   void shareFile(File f){
       sharedFiles.add(f);
   }


class File {
   Set<User> sharedUsers;
   void shareWith(User u){
       sharedUsers.add(u);
   }
}

main(){
   User u = new User();
   File f = new File();
   u.shareFile(f);
   f.shareWith(u);
}

答案 3 :(得分:0)

为了更好的设计,你不应该有这样的循环依赖。

用户不依赖于他共享的文件。

该文件不依赖于与之共享的用户。

考虑这样的事情:

class User {
    String firstName, lastName; // or something
}
class File {
    String filename, path; // or something
}

class Sharestorage {
    Map<User,Set<File>> userToFiles = new HashMap<>();
    Map<File,Set<User>> fileToUsers = new HashMap<>();
    public void share(User u, File f) {
        Set<File> files = userToFiles.computeIfAbsent(u, new HashSet<>());
        files.add(f);
        userToFiles.put(u, files);
        Set<User> users = fileToUsers.computeIfAbsent(f, new HashSet<>());
        users.add(u);
        fileToUsers.put(users);
    }
    public Set<File> getFilesSharedBy(User u) {
        return userToFiles.computeIfAbsent(u, Collections.emptySet());
    }
    public Set<User > getFilesSharedBy(File f) {
        return fileToUsers.computeIfAbsent(f, Collections.emptySet());
    }
}

答案 4 :(得分:0)

改进伊兰的答案,你可以写

class User {
       Set<File> sharedFiles;
       boolean hasFile (File f) {
           return sharedFiles.contains(f);
       }
       void shareFile(File f){
           if (!sharedFiles.contains(f))
               sharedFiles.add(f);
               f.shareWith(this);
           }
       }
}

class File {
       Set<User> sharedUsers;
       boolean hasUser (User u) {
           return sharedUsers.contains(u);
       }
       void shareWith(User u){
           if (! sharedUsers.contains(f))
               sharedUsers.add(u);
               u.shareFile(this);
           }
       }
}

这样您就不需要实施其他方法了。