2016-04-26 42 views
0

所以我有一些存儲在MySQL數據庫中的朋友系統的數據,以及一些API來檢索Java對象中的數據。 (MPlayer)包含諸如用戶名,在線狀態,朋友(由「:」分隔的ID)之類的東西。 MPlayer對象將玩家的唯一ID作爲構造函數。我該如何解決這個遞歸的StackOverFlowException錯誤?

創建時以及調用reload()方法時,數據保存在對象中。這不是每次我想獲得像用戶名這樣的東西時訪問數據庫。原因是我需要將數據放到一個循環中才能顯示在GUI上,而且我顯然不希望每幀都下載數據。相反,我只是每6秒左右使用重載方法。

其中一個函數是getFriends()並返回MPlayer的列表。該列表在MPlayer對象創建時存儲。問題是,當每個MPlayer朋友被創建時,它會爲他們的朋友創建一個列表,然後爲他們的朋友創建一個列表,最後由於遞歸而結束StackOverFlowException。

什麼是避免錯誤的好方法?

代碼中的問題:

MPlayer的構造函數/ load方法:

public MPlayer(String player){ 
    this.uuid = player; 
    try { 
     st.setString(1, uuid); 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 
    this.reload(); 
} 

public void reload(){ 
    try { 
     ResultSet set = st.executeQuery(); 
     if(set.next()){ 
      if(set.getString("server").equals("none")){ 
       isConnected = false; 
      }else{ 
       isConnected = true; 
      } 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 

    try { 
     ResultSet set = st.executeQuery(); 
     if(set.next()){ 
      this.serverIP = set.getString("server"); 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 



    try { 

     ResultSet set = st.executeQuery(); 
     if(set.next()){ 
      this.username = set.getString("username"); 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 


    try { 
     ResultSet get = st.executeQuery(); 
     if(get.next()){ 
      this.online = get.getBoolean("status"); 
     } 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 
    try { 


     List<MPlayer> list = new ArrayList<MPlayer>(); 
     ResultSet get = st.executeQuery(); 
     if(get.next()){ 
      for(String str : get.getString("friends").split(":")){ 
       if(!str.equalsIgnoreCase("none")){ 
        MPlayer player = new MPlayer(str); 
        if(player.isOnline()){ 
         list.add(0,player); 
        }else{ 
         list.add(player); 
        } 
       } 
      } 

     } 
     this.friends = list; 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 


    this.settings = new Settings(this); 


    PreparedStatement state = Main.getPreparedStatement("SELECT * FROM updates WHERE uuid=?"); 
    try { 
     state.setString(1, this.getUUID()); 
     ResultSet set2 = state.executeQuery(); 
     List<StatusUpdate> updates = new ArrayList<StatusUpdate>(); 

     while(set2.next()){ 
      updates.add(new StatusUpdate(set2.getInt(1))); 
     } 
      Collections.sort(updates, new Comparator<StatusUpdate>() { 
       @Override 
       public int compare(StatusUpdate r1, StatusUpdate r2) { 

        return -1 * r1.getDate().compareTo(r2.getDate()); 
       } 
      }); 

     this.updates = updates; 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 


    List<StatusUpdate> updates = new ArrayList<StatusUpdate>(); 

    for(MPlayer p : this.getFriends()){ 
     updates.addAll(p.getStatusUpdates()); 

    } 
    updates.addAll(this.getStatusUpdates()); 
    Collections.sort(updates, new Comparator<StatusUpdate>() { 
     public int compare(StatusUpdate m1, StatusUpdate m2) { 

      return -1 * m1.getDate().compareTo(m2.getDate()); 
     } 
    }); 
    this.timeline = updates; 



} 
+1

請發佈您的代碼和確切的錯誤。 [關於SO的問題](http://stackoverflow.com/help/how-to-ask)。 – Dresden

+0

這裏的問題是,你正在從'reload'函數中調用'MPlayer player = new MPlayer(str)',但是在'MPlayer'的構造函數中,你也調用'this.reload();'這也會調用'MPlayer播放器=新的MPlayer(str);'所以循環是無限的 - 我認爲第一步應該是重構你的代碼 - 這不是一個好主意,你的'reload'函數做的太多了...... – ishmaelMakitla

回答

0

答案顯然是 「退出,無終止遞歸這樣做」。

你不想在朋友列表上無限的關閉 - 但你想要什麼?只是朋友的名單?在這種情況下,也許你需要一個單獨的對象類型,比如「FriendList」。在創建這個時,你只需列出好友ID;不要加載朋友記錄,直到它被明確訪問。

另一種方法是編碼要激活的級別數,使其成爲對象加載的參數。對於isntance,加載深度爲N = 2的主MPlayer。對於主要的每個朋友,加載深度爲N-1。當你點擊0時,列出ID而不加載記錄(如上所述)。

這是否讓您朝着解決方案邁進?

+0

我明白了。某種只讀選手對象?謝謝你,你是少數幾個人不是「你做得完全錯誤,重做你的代碼,然後再回來」的例子之一。 –

+0

你很受歡迎。是的,只讀是查看它的一種方式。最重要的是,您只需要將衍生案例與主要派生案例分開,以打破無限遞歸。 – Prune

+0

我同意其他人的看法,認爲你的代碼似乎不是「自然的方式」去思考它,但我認爲你比我們更瞭解你的問題空間。 :-)例如,您的方法可能會支持您尚未實現的功能。 – Prune

相關問題