【问题标题】:Arraylist<> is null although it's initialized in the constructorArraylist<> 为 null,尽管它已在构造函数中初始化
【发布时间】:2018-07-18 08:52:30
【问题描述】:

我在java中做了一个小的httpserver,你知道它应该是静态的,我需要一个小型数据库,所以决定做一个内存数据库。问题是数据库类应该是静态的才能在服务器内部使用它。

所以我改变了主意,尝试将数据存储在 json 文件中,每次需要数据时,只需从文件中读取即可。为了简短起见,我需要使用一个数组列表。它在构造函数中初始化。但是当涉及到使用它时,它是空的:|

这是我的代码:

public class DbContext {

private ArrayList<Player> players;

public DbContext() {
    this.players = new ArrayList<>();
    readPlayer();
}

public Player getPlayerByIds(long id, long boardId) {
    for (Player p : players) {
        if (p.getBoardId() == boardId && p.getId() == id) {
            writePlayer();
            return p;
        }
    }

    return null;
}

public boolean updatePlayer(Player player) {
    for (Player p : players) {
        if (p.getId() == player.getId()) {
            p = player;
            writePlayer();
            return true;
        }
    }

    return false;
}

public void addPlayer(Player player) {
    players.add(player);
    writePlayer();
}

private boolean playerExists(Player player) {
    for (Player p : players) {
        if (p.getId() == player.getId()) {
            return true;
        }
    }

    return false;
}

private void readPlayer() {
    Gson gson = new Gson();
    try {
        BufferedReader br = new BufferedReader(new FileReader("players.json"));
        if (br.read() > 0) {
            players = gson.fromJson(br, new TypeToken<ArrayList<Player>>() {
            }.getType());
        }
    } catch (FileNotFoundException ex) {
        Logger.getLogger(DbContext.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(DbContext.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private void writePlayer() {
    Gson gson = new Gson();
    try (FileWriter writer = new FileWriter("players.json")) {
        gson.toJson(players, writer);
        writer.flush();
        writer.close();
    } catch (IOException ex) {
        Logger.getLogger(DbContext.class.getName()).log(Level.SEVERE, null, ex);
    }
}

任何帮助或建议将不胜感激。谢谢大家

【问题讨论】:

  • 您正在为它分配一个值 - players = gson.fromJson(br, new TypeToken&lt;ArrayList&lt;Player&gt;&gt;() {}.getType()); - 也许该值为 null。
  • 基于@Eran 的评论,使players 成员final 并使用List.clear()List.addAll() 这样你可能会得到一个NullPointerException,但是你知道你的问题可能在哪里谎言
  • 是的,不要在构造函数中初始化你的arraylist,它没有必要,因为你用 line player = gson.fromJson 覆盖它..它只会污染内存......调试你的代码并检查返回值getType 的
  • 最好使用私有列表 readPlayer() {.. return list;} 。它也可以在课外重复使用。
  • @SumeshTG 这里的问题不是设计;)我想他只是想知道为什么他有空指针,设计来了:D

标签: java json arraylist constructor


【解决方案1】:

可能只是找不到文件。如果将文件放在源根目录中(例如标准 maven 项目中的 src/main/resources/),则可以使用

从类路径中读取它
InputStream in = this.getClass().getClassLoader().getResourceAsStream(PLAYERS_FILE);

我会稍微重构一下代码,例如:

import java.io.*;
import java.util.*;

public class DbContext {

    // use constants, not String literals
    public static final String PLAYERS_FILE = "players.json";

    // use interfaces where possible rather than concrete implementation type
    private List<Player> players;

    public DbContext() {
        // the initialization was always overwritten
        // just assign directly from the method
        this.players = readPlayers();
    }

    public Optional<Player> getPlayerByIds(long id, long boardId) {
        for (Player p : players) {
            if (p.getBoardId() == boardId && p.getId() == id) {
                // no need to write players here since there is no change
                // writePlayers();
                return Optional.of(p);
            }
        }
        // do not return null from a method, use Optional instead
        return Optional.empty();
    }

    public void updatePlayer(Player player) {

        // this will not work. player will not get added in the list if you reassign a local variable
        // for (Player p : players) {
        //    if (p.getId() == player.getId()) {
        //        p = player;

        Optional<Integer> playerIndex = findPlayer(player);
        if (playerIndex.isPresent()) {
            players.set(playerIndex.get(), player);
        } else {
            // if the player is not found you can either add the player
            addPlayer(player);
            // ... or throw an exception
            // throw new DbContextException(String.format("Could not find player to update: %s", player));
            // returning a boolean to indicate failure is sort of evil
        }
    }

    private Optional<Integer> findPlayer(Player player) {
        for (int i = 0; i < players.size(); i++) {
            if (players.get(i).getId() == player.getId()) {
                return Optional.of(i);
            }
        }
        return Optional.empty();
    }

    public void addPlayer(Player player) {
        // if you want players to be unique in the list, you should do some checking here
        players.add(player);
        writePlayers();
    }

    // never used
//    private boolean playerExists(Player player) {
//        for (Player p : players) {
//            if (p.getId() == player.getId()) {
//                return true;
//            }
//        }
//        return false;
//    }

    // refactored methods below so each method does only one thing, or at least operates at a single level of abstraction

    private List<Player> readPlayers() {
        try (BufferedReader br = new BufferedReader(new FileReader(PLAYERS_FILE))) {
            return readPlayers(br);
        } catch (IOException e) {
            // DbContextException extends RuntimeException
            throw new DbContextException(String.format("Could not read players from %s", PLAYERS_FILE), e);
        }
    }

    private List<Player> readPlayers(BufferedReader br) throws IOException {
        List<Player> players;
        if (br.read() > 0) {
            players = readPlayersAvailable(br);
        } else {
            players = new ArrayList<>();
        }
        return players;
    }

    private List<Player> readPlayersAvailable(BufferedReader br) {
        List<Player> players;
        Gson gson = new Gson();
        // this looks hacky. in Gson 2.8.0 you can use TypeToken.getParameterized(ArrayList.class, Player.class).getType()
        Type type = new TypeToken<ArrayList<Player>>() {
        }.getType();
        players = gson.fromJson(br, type);
        return players;
    }

    private void writePlayers() {
        try (FileWriter writer = new FileWriter(PLAYERS_FILE)) {
            writePlayers(writer);
        } catch (IOException e) {
            throw new DbContextException(String.format("Could not write players to %s", PLAYERS_FILE), e);
        }
    }

    private void writePlayers(FileWriter writer) throws IOException {
        Gson gson = new Gson();
        gson.toJson(players, writer);
        writer.flush();
    }
}

在我看来,readPlayersAvailable 中的代码不起作用。我建议看一下 Gson(也许切换到更新的版本)并检查 fileReader 是否确实找到了您的文件。

【讨论】:

  • 谢谢哥们。看起来很棒,但仍然无法正常工作。这可能是从文件中读取。
  • 实际上阅读部分似乎很好,但无法转换为我的自定义对象。 @Adriaan
  • 可能是。我们需要有关 Player 类、文件中的 JSON 以及您将获得帮助的异常的更多信息。
【解决方案2】:

感谢“Adriaan Koster”和“Sumesh TG”,我终于找到了解决方案。看来 gson 无法将 json 转换为我的班级。所以我决定手动解析它。

String currentLine;
List<Player> playerList = new ArrayList<>();
while ((currentLine = br.readLine()) != null) {
    Player p = new Gson().fromJson(currentLine, Player.class);
    System.out.println(p.toString());
    playerList.add(p);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-27
    • 1970-01-01
    • 2013-10-29
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 2013-08-28
    相关资源
    最近更新 更多