【问题标题】:How can I fix this recursive StackOverFlowException error?如何修复此递归 StackOverFlowException 错误?
【发布时间】:2016-04-27 03:12:57
【问题描述】:

所以我有一种存储在 MySQL 数据库中的朋友系统的数据,以及一种用于检索 Java 对象中数据的 API。

Java 对象 (MPlayer) 包含诸如用户名、在线状态、朋友(ID 以“:”分隔)之类的内容。 MPlayer 对象将播放器的唯一 ID 作为构造函数。

数据在创建时和调用 reload() 方法时保存在对象中。这不是每次我想获得用户名之类的东西时都访问数据库。这样做的原因是我需要循环获取数据以显示在 GUI 上,而且我显然不想每帧都下载数据。相反,我只是每 6 秒左右使用一次 reload 方法。

其中一个函数是getFriends(),它返回一个MPlayer 列表。该列表在创建 MPlayer 对象时存储。问题是,当每个 MPlayer 好友被创建时,它会为他们的好友创建一个列表,而后者又会为他们的好友创建一个列表,最终由于递归而导致 StackOverFlowException。

什么是避免错误的好解决方案?

有问题的代码:

MPlayer 构造器/加载方法:

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;



}

【问题讨论】:

  • 请发布您的代码以及您遇到的确切错误。 Questions on SO.
  • 这里的问题是您正在从 reload 函数调用 MPlayer player = new MPlayer(str) - 但在 MPlayer 的构造函数中,您还调用了 this.reload();,它也将调用 MPlayer player = new MPlayer(str); 和所以循环是无限的——我认为第一步应该是重构你的代码——你的reload函数做了这么多不是一个好主意......

标签: java mysql recursion stack-overflow


【解决方案1】:

显而易见的答案是“以递归方式退出,没有终止”。

您不希望好友列表无限关闭——但是您想要做什么?只是好友列表?在这种情况下,也许您需要一个单独的对象类型,例如“FriendList”。在创建它时,您只需列出朋友 ID;在明确访问之前不要加载朋友记录。

另一种方法是编码要激活的级别数,使其成为对象负载的参数。例如,加载深度为 N=2 的主 MPlayer。对于您主要的每个朋友,加载到 N-1 的深度。当您点击 0 时,列出 ID 而不加载记录(如上)。

这是否会让您朝着解决方案前进?

【讨论】:

  • 我明白了。某种只读播放器对象?谢谢,你是少数几个没有“你做错了,重做代码,稍后再回来”的例子之一。
  • 不客气。是的,只读是查看它的一种方式。最重要的是,您只需要将衍生案例与主要案例分开,即可打破无限递归。
  • 我同意其他人的观点,即您的代码似乎不是思考它的“自然方式”,但我认为您比我们更了解您的问题空间。 :-) 例如,您的方法可能很好地支持您尚未实现的功能。
猜你喜欢
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
  • 1970-01-01
  • 2020-02-22
  • 2014-03-01
  • 2012-07-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多