You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX聊天应用调用Getter时出现NullPointerException问题求助

NullPointerException when accessing TextArea from Client class in JavaFX Chat App

问题背景

使用Java 17结合JavaFX(FXML)和Socket开发聊天应用,已实现与服务器通信,但在Client.java中调用appController.getMessageArea().getText()时触发NullPointerException,错误日志如下:

java.lang.NullPointerException: Cannot invoke "javafx.scene.control.TextArea.getText()" because the return value of "messageapp.AppController.getMessageArea()" is null
    at messageapp/messageapp.util.Client.send(Client.java:35)
    at messageapp/messageapp.AppController.send(AppController.java:47)
    ...(省略后续堆栈信息)

相关代码

Client.java

public class Client {

    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private String username;
    private AppController appController;

    public Client(Socket socket, String username) throws IOException {
        this.appController = new AppController();
        try {
            this.socket = socket;
            this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.out = new PrintWriter(socket.getOutputStream(), true);
            this.username = username;
            out.println(username);
        } catch (IOException e) {
            closeAll();
        }
    }

    public void send() {
        String message;
        try {
            while(socket.isConnected()){
                message = appController.getMessageArea().getText();
                out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //closeAll(socket, in, out);
        }
    }

    public void closeAll(Closeable... objects){
        for(Closeable c : objects){
            try {
                c.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void listen(){
        new Thread(() -> {
            String receivedMessage;
            while(socket.isConnected()){
                try{
                    receivedMessage = in.readLine();
                    Label received = new Label(receivedMessage);
                    appController.getMessageContainer().getChildren().add(received);
                    appController.getScrollPane().setVvalue(1.0);

                }catch(Exception e){
                    closeAll(socket, in, out);
                }

            }
        }).start();
    }

    public Socket getSocket() {
        return socket;
    }

    public String getUsername() {
        return username;
    }
}

AppController.java

public class AppController implements Initializable {

    @FXML
    private TextArea messageArea;
    @FXML
    private VBox messageContainer;
    @FXML
    private ScrollPane scrollPane;
    @FXML
    private Label nameTag;
    @FXML
    private Button sendButton;

    private Client client;


    @Override
    public void initialize(URL url, ResourceBundle resources){
        try{
            System.out.println(getMessageArea());
            messageArea.clear();
            sendButton.disableProperty().bind(messageArea.textProperty().isEmpty());
            nameTag.setText(LoginController.user.getName());
            client = new Client(new Socket("localhost", 1234), LoginController.user.getName());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void send(){
       //String message = messageArea.getText();
       Label sent = new Label(client.getUsername() + "> " + messageArea.getText());
       messageContainer.getChildren().add(sent);
       scrollPane. setVvalue(1.0);
       client.send();
       messageArea.clear();

    }

    public VBox getMessageContainer() {
        return messageContainer;
    }

    public ScrollPane getScrollPane() {
        return scrollPane;
    }

    public TextArea getMessageArea() {
        return messageArea;
    }
}

问题根源

Client构造函数中自行创建了new AppController()实例,这个实例不是由FXML加载器初始化的,因此@FXML注解的messageArea等控件从未被注入,调用getMessageArea()会返回null,进而触发NPE。

解决方案

1. 修改Client构造函数,接收外部传入的AppController

public class Client {

    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private String username;
    private AppController appController;

    // 修改构造函数,接收已初始化的AppController
    public Client(Socket socket, String username, AppController appController) throws IOException {
        this.appController = appController; // 使用传入的实例,而非新建
        try {
            this.socket = socket;
            this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.out = new PrintWriter(socket.getOutputStream(), true);
            this.username = username;
            out.println(username);
            // 启动监听线程
            listen();
        } catch (IOException e) {
            closeAll(socket, in, out);
        }
    }

    // 修改send方法:移除while循环,单次发送当前消息
    public void send(String message) {
        try {
            if(socket.isConnected() && message != null && !message.isBlank()){
                out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
            closeAll(socket, in, out);
        }
    }

    // 其余方法保持不变...
}

2. 修改AppController的initialize方法,创建Client时传入自身实例

@Override
public void initialize(URL url, ResourceBundle resources){
    try{
        System.out.println(getMessageArea());
        messageArea.clear();
        sendButton.disableProperty().bind(messageArea.textProperty().isEmpty());
        nameTag.setText(LoginController.user.getName());
        // 创建Client时传入当前AppController实例
        client = new Client(new Socket("localhost", 1234), LoginController.user.getName(), this);
    }catch (Exception e){
        e.printStackTrace();
    }
}

public void send(){
   String message = messageArea.getText();
   Label sent = new Label(client.getUsername() + "> " + message);
   messageContainer.getChildren().add(sent);
   scrollPane.setVvalue(1.0);
   // 传入消息内容给Client的send方法
   client.send(message);
   messageArea.clear();
}

关键修改说明

  • 让Client持有正确的AppController实例:通过构造函数传入FXML加载器初始化好的AppController,确保@FXML控件已被正确注入。
  • 调整send方法逻辑:移除Client.send中的while循环,因为每次点击发送按钮只需要发送当前输入的一条消息,循环会导致重复发送且阻塞线程;改为直接传入消息内容进行发送,逻辑更清晰。

内容的提问来源于stack exchange,提问作者Anthrax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 19:21:59