How to add object again after filtering array with non-null object

大城市里の小女人 提交于 2020-05-15 21:20:48

问题


I am building a classical Nim game using only the array, and I found there is a bug after testing. If I successfully create a player, I'll assign a new object to the array. However, when removing the player in the array, I filter the array with non-null objects because I have other functions such as editplayer, displayplayer to iterate the entire array without NullPointerException.

And there is a chance that this happens: addplayerremoveplayeraddplayer. It means I'll always get IndexOutOfBound when I try to assign a new object to the array already full of the non-null objects.

I've searched for all the information I could, but there is no such discussion about this. Is there any way to avoid both NullPointerException and IndexOutOfBound at the same time?

Here is related code Nimsys:

public class Nimsys {

public static void addPlayer(String [] name) {
    if (name != null && name.length == 3) {
        for (int i = 0; i < NimPlayer.getCounter(); i++) {
            String userCheck = NimPlayer.getPlayer()[i].getUserName();
            if (userCheck.contains(name[0])) {
                System.out.println("The player already exists.\n");// Test if player has been created
                return;
            }
        }
        NimPlayer.createPlayer(name[0], name[1], name[2]);
        System.out.println("The player has been created.");
        return;
    } 
    System.out.println("Not Valid! Please enter again!");   
}

public static void searchAndRemovePlayer(String user) {
    NimPlayer [] playerList = NimPlayer.getPlayer();
    for (int i = 0; i < playerList.length; i++) {
        String userName =playerList[i].getUserName().trim();
        if (userName.equals(user)) {
            playerList[i] = null;
            System.out.println("Remove successfully!");
            NimPlayer.setPlayerList(playerList);
            return;
        }
    }
    System.out.println("The player does not exist.\n");

}
}

Here is part of NimPlayer class:

public class NimPlayer {
private String userName;
private String familyName;
private String givenName;
private int score;
private int gamePlayed;

private static int counter;
private static final int SIZE = 10;
private static NimPlayer[] playerList = new NimPlayer[SIZE]; // set an array here


//define NimPlayer data type
public NimPlayer(String userName, String surName, String givenName) {
    this.userName = userName;
    this.familyName = surName;
    this.givenName = givenName;

}
// create new data using NimPlayer data type
public static void createPlayer(String userName, String familyName, String givenName) {
    if (counter < SIZE) {
        playerList[counter++] = new NimPlayer(userName, familyName, givenName);
    } else {
        System.out.println("Cannot add more players.");
    }
}
public static int getCounter() {
    return counter;
}
public static NimPlayer [] getPlayer() {      
    return playerList;
}
public static void setPlayerList(NimPlayer [] newplayerList) {
    playerList = Arrays.stream(newplayerList).filter(Objects::nonNull).toArray(NimPlayer[]::new);
    counter = playerList.length;  //update the counter
}
    //setters and getters of the other variables
}

回答1:


  1. Instead of explaining about these exceptions, I recommend you go through the documentation of NullPointerException and ArrayIndexOutOfBoundsException. It is not a big deal to handle these exceptions when they occur. However, the most important thing is to prevent them i.e. you should understand what is the root cause and work on them. We all know, "Prevention is better than cure.".
  2. You should always try to hide as much information from the class as is possible e.g. you already have a public static void createPlayer then, why have you created a public constructor? Why have you created a public getter for counter which is meant to be used only internally in the class, NimPlayer?
  3. Instead of exposing the playerList to be set from outside, you should remove its public setter and create public static void removePlayer similar to public static void createPlayer.

On a side note (because it won't affect the execution of the program), the name of an identifier should be self-explanatory e.g. your getPlayer method should be named as getPlayerList as it is returning the playerList, not a single player.

Given below is the code incorporating these comments:

import java.util.Arrays;
import java.util.Objects;

class NimPlayer {
    private String userName;
    private String familyName;
    private String givenName;
    private int score;
    private int gamePlayed;

    private static int counter;
    private static final int SIZE = 10;
    private static NimPlayer[] playerList = new NimPlayer[SIZE];

    private NimPlayer(String userName, String surName, String givenName) {
        this.userName = userName;
        this.familyName = surName;
        this.givenName = givenName;
    }

    public static void createPlayer(String userName, String familyName, String givenName) {
        if (counter < SIZE) {
            playerList[counter++] = new NimPlayer(userName, familyName, givenName);
        } else {
            System.out.println("Cannot add more players.");
        }
    }

    public static void removePlayer(NimPlayer player) {
        int i;
        for (i = 0; i < playerList.length; i++) {
            if (playerList[i] != null && playerList[i].getUserName().equals(player.getUserName())) {
                break;
            }
        }
        for (int j = i; j < playerList.length - 1; j++) {
            playerList[j] = playerList[j + 1];
        }
        counter--;
    }

    public static NimPlayer[] getPlayerList() {
        return Arrays.stream(playerList).filter(Objects::nonNull).toArray(NimPlayer[]::new);
    }

    public String getUserName() {
        return userName;
    }

    public String getFamilyName() {
        return familyName;
    }

    public String getGivenName() {
        return givenName;
    }

    @Override
    public String toString() {
        return userName + " " + familyName + " " + givenName;
    }
}

class NimSys {

    public static void addPlayer(String[] name) {
        if (name != null && name.length == 3) {
            NimPlayer[] playerList = NimPlayer.getPlayerList();
            for (int i = 0; i < playerList.length; i++) {
                String userCheck = playerList[i].getUserName();
                if (userCheck.contains(name[0])) {
                    System.out.println("The player, " + name[0] + " already exists.\n");
                    return;
                }
            }
            NimPlayer.createPlayer(name[0], name[1], name[2]);
            System.out.println("The player, " + name[0] + "  has been created.");
            return;
        }
        System.out.println("Not Valid! Please enter again!");
    }

    public static void searchAndRemovePlayer(String user) {
        NimPlayer[] playerList = NimPlayer.getPlayerList();
        for (int i = 0; i < playerList.length; i++) {
            String userName = playerList[i].getUserName().trim();
            if (userName.equals(user)) {
                NimPlayer.removePlayer(playerList[i]);
                System.out.println("The player, " + user + " removed successfully!");
                return;
            }
        }
        System.out.println("The player, " + user + "  does not exist.\n");
    }

    public static void displayPlayerList() {
        NimPlayer[] playerList = NimPlayer.getPlayerList();
        StringBuilder sb = new StringBuilder();
        for (NimPlayer player : playerList) {
            sb.append(player.getUserName()).append(" ").append(player.getFamilyName()).append(" ")
                    .append(player.getGivenName()).append(System.lineSeparator());
        }
        System.out.println(sb);
    }
}

public class Main {
    public static void main(String[] args) {

        NimSys.addPlayer(new String[] { "Harry", "Potter", "Harry" });
        NimSys.displayPlayerList();

        NimSys.searchAndRemovePlayer("Harry");
        NimSys.displayPlayerList();

        NimSys.addPlayer(new String[] { "Manny", "Richard", "Canty" });
        NimSys.displayPlayerList();

        NimSys.addPlayer(new String[] { "Arvind", "Kumar", "Avinash" });
        NimSys.displayPlayerList();

        NimSys.searchAndRemovePlayer("Manny");
        NimSys.displayPlayerList();

        NimSys.addPlayer(new String[] { "Ken", "Ken", "Thompson" });
        NimSys.displayPlayerList();

        NimSys.searchAndRemovePlayer("Ken");
        NimSys.displayPlayerList();

        NimSys.addPlayer(new String[] { "Ken", "Ken", "Thompson" });
        NimSys.displayPlayerList();

        NimSys.searchAndRemovePlayer("Ken");
        NimSys.displayPlayerList();

        NimSys.addPlayer(new String[] { "Ken", "Ken", "Thompson" });
        NimSys.displayPlayerList();
    }
}

Output:

The player, Harry  has been created.
Harry Potter Harry

The player, Harry removed successfully!

The player, Manny  has been created.
Manny Richard Canty

The player, Arvind  has been created.
Manny Richard Canty
Arvind Kumar Avinash

The player, Manny removed successfully!
Arvind Kumar Avinash

The player, Ken  has been created.
Arvind Kumar Avinash
Ken Ken Thompson

The player, Ken removed successfully!
Arvind Kumar Avinash

The player, Ken  has been created.
Arvind Kumar Avinash
Ken Ken Thompson

The player, Ken removed successfully!
Arvind Kumar Avinash

The player, Ken  has been created.
Arvind Kumar Avinash
Ken Ken Thompson



回答2:


To answer your question: "Is there any way to avoid both NullPointerException and IndexOutOfBound at the same time?"

Yes, you can do that by using the following two things.

First, you can get the length of the array using its length property. length is the number of elements in the array (including those whose value is null). With that information you should never be indexing out of bounds (as long as you're not writing concurrent code that modifies the array's length).

Secondly, you need to check what you take out of the array to see if it is null. You can just do that with an if statement.

Here's what that would look like:

// create an array with 5 elements. 0, 2, and 4 are null. 1 and 3 are not null.
String[] myArray = new String[5];
myArray[1] = "abc ";
myArray[3] = "def";

// myArray.length will be '5'
for (int i = 0; i < myArray.length; i++){
  String value = myArray[i];

  if (value != null) {
    // prints "ABC DEF" and doesn't result in a NullPointer
    System.out.print(value.toUpperCase());
  }
}

So in your case:

public static void addPlayer(String [] name) {
    if (name != null && name.length == 3) {
        for (int i = 0; i < NimPlayer.getPlayer().length; i++) {
            NimPlayer player = NimPlayer.getPlayer()[i];

            if (player != null && player.getUserName().contains(name[0]))
                System.out.println("The player already exists.\n");
                return;
            }
        }
        NimPlayer.createPlayer(name[0], name[1], name[2]);
        System.out.println("The player has been created.");
        return;
    } 
    System.out.println("Not Valid! Please enter again!");   
}

And just to add. In object oriented programming you generally want to follow the principle of encapsulation - so you probably want to move the methods in NimSys into NimPlayer since they operate on the data in NimPlayer.

I'm guessing you're new to Java and programming. Good luck learning!



来源:https://stackoverflow.com/questions/61494092/how-to-add-object-again-after-filtering-array-with-non-null-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!