Java实现空指针后的猜拳游戏

Java
313
0
0
2023-02-20
目录
  • 前言
  • 插件实现
  • 创建项目
  • 猜拳游戏实现
  • 游戏弹窗实现
  • 监听空指针异常
  • 安装插件
  • 演示
  • 最后

前言

“java.lang.NullPointerException” 空指针异常可以说是Java程序最容易出现的异常了,我写了一个 IDEA 插件,每当程序出现空指针异常时就会弹出一个“猜拳游戏”窗口,该窗口不能直接关闭,只有当你游戏获胜时,窗口才会自动关闭。

作用是啥?

嘲讽罢了。

插件实现

创建项目

IDEA 创建一个插件开发项目非常方便,已经内置了。

猜拳游戏实现

很简单。

实现原理:提供3个按钮,分别为“石头、剪刀、布”,对应值“1、2、3”,再为按钮绑定点击事件,按键点击之后调用处理函数传入对应的值即可。

处理函数 handle(int selectedValue) 的实现:利用随机数随机为电脑生成一个值与用户选择的值做比较,“石头赢剪刀、剪刀赢布、布赢石头”,然后显示游戏结果,用户获胜时会触发回调函数(用于关闭弹窗)。

package cn.xeblog.mora.ui;

import javax.swing.*;
import java.awt.*;
import java.util.Random;

/**
 * @author anlingyi
 * @date 2022/8/11 8:02 PM
 */
public class MoraGame extends JPanel {

    /**
     * 猜拳获胜调用
     */
    private Runnable runnable;

    /**
     * 提示标签
     */
    private JLabel tipsLabel;

    /**
     * 结束标记
     */
    private boolean isOver;

    public MoraGame(Runnable runnable) {
        setMinimumSize(new Dimension(250, 100));
        setLayout(new BorderLayout());
        this.runnable = runnable;
        init();
    }

    private void init() {
        this.tipsLabel = new JLabel("请出拳!", JLabel.CENTER);
        this.tipsLabel.setPreferredSize(new Dimension(250, 50));
        this.tipsLabel.setFont(new Font("", 0, 15));
        this.tipsLabel.setForeground(new Color(255, 128, 128));

        JButton stoneButton = new JButton("石头");
        JButton shearsButton = new JButton("剪刀");
        JButton clothButton = new JButton("布");

        stoneButton.setFocusPainted(false);
        stoneButton.setBorderPainted(false);
        stoneButton.addActionListener(l -> handle(1));

        shearsButton.setFocusPainted(false);
        shearsButton.setBorderPainted(false);
        shearsButton.addActionListener(l -> handle(2));

        clothButton.setFocusPainted(false);
        clothButton.setBorderPainted(false);
        clothButton.addActionListener(l -> handle(3));

        JPanel centerPanel = new JPanel();
        centerPanel.setPreferredSize(new Dimension(250, 30));
        centerPanel.add(stoneButton);
        centerPanel.add(shearsButton);
        centerPanel.add(clothButton);

        add(tipsLabel, BorderLayout.NORTH);
        add(centerPanel, BorderLayout.CENTER);
    }

    private void handle(int selectedValue) {
        if (isOver) {
            return;
        }

        int value = new Random().nextInt(3) + 1;
        boolean isWin = selectedValue == (value - 1 == 0 ? 3 : value - 1);

        String result;
        if (isWin) {
            isOver = true;
            result = "你赢~";
        } else if (selectedValue == value) {
            result = "平局~";
        } else {
            result = "电脑赢~";
        }
        showTips("电脑 -> " + getText(value) + ",你 -> " + getText(selectedValue) + "," + result);

        if (isWin) {
            new Thread(() -> {
                try {
                    Thread.sleep(800);
                    this.runnable.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }
    }

    private String getText(int value) {
        switch (value) {
            case 1:
                return "石头";
            case 2:
                return "剪刀";
            case 3:
                return "布";
        }

        return "";
    }

    private void showTips(String tips) {
        tipsLabel.setText(tips);
    }

}

游戏弹窗实现

将窗口设置为不可关闭,传递弹窗关闭回调函数到游戏处理对象。

package cn.xeblog.mora.ui;

import com.intellij.openapi.ui.DialogWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

/**
 * @author anlingyi
 * @date 2022/8/11 7:58 PM
 */
public class MoraDialog extends DialogWrapper {

    public MoraDialog() {
        super(true);
        setTitle("猜拳游戏?");
        setResizable(false);
        setCrossClosesWindow(false);
        init();
    }

    @Override
    protected @Nullable JComponent createCenterPanel() {
        return new MoraGame(() -> SwingUtilities.invokeLater(() -> this.close(0)));
    }

    @Override
    protected @NotNull Action[] createActions() {
        return new Action[]{};
    }

}

监听空指针异常

实现控制台过滤接口,判断控制台的输出内容是否包含 java.lang.NullPointerException ,如果包含则弹出游戏窗口。

package cn.xeblog.mora.filter;

import cn.xeblog.mora.ui.MoraDialog;
import com.intellij.execution.filters.ConsoleFilterProvider;
import com.intellij.execution.filters.Filter;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;

/**
 * @author anlingyi
 * @date 2022/8/11 11:46 PM
 */
public class ConsoleFilter implements ConsoleFilterProvider {

    @Override
    public Filter @NotNull [] getDefaultFilters(@NotNull Project project) {
        return new Filter[]{(line, entireLength) -> {
            if (line.contains("java.lang.NullPointerException")) {
                SwingUtilities.invokeLater(() -> new MoraDialog().show());
            }

            return null;
        }};
    }

}

注册过滤器

plugin.xml 添加我们自定义的控制台过滤器实现。

    <extensions defaultExtensionNs="com.intellij">
        <consoleFilterProvider implementation="cn.xeblog.mora.filter.ConsoleFilter"/>
    </extensions>

安装插件

插件打包

Gradle -> Tasks -> build -> assemble

打包之后的文件位于项目的 build 目录下:build/distributions/xxx.zip

插件安装

进入插件中心,选择本地文件安装即可。

演示

会出现空指针的代码

    public static void main(String[] args) {
        Object obj = null;
        System.out.println(obj.toString());
    }

运行之后

当我猜拳赢了之后,窗口就自动关闭了。

最后

完整代码:https://github.com/anlingyi/Mora