2

I have a problem with my minecraft plugin. I want to add objects of player to a list. Before that, I want to check if the player already exist in my list.

Here an Example:

public class Player{

    public String playerName;
    public int Count = 0;

    public Player(String name){

         playerName = name;
    }
}

Here the main class:

public class mainClass{ 
   List<Player> = PlayerList;
   [...]
   if(!(*An object with attribute examplename in List exist*)){
        Player p = new Player("eamplename") 
        PlayerList.Add(p);
   }
}
Chris Martin
  • 30,334
  • 10
  • 78
  • 137

2 Answers2

2

I would suggest two ways to solve your problem. The first one is to stick with your approach of using List.

    List<Foo> list = new ArrayList<Foo>();

    boolean hasMyItem = false;
    String newName = "hello world";

    for (Foo foo : list)        // iterate over each item in the list
    {
        if (foo.name.equals(newName))
        {
            hasMyItem = true;
            break;            // get out of for loop
        }
    }

    if (!hasMyItem)
    {
        list.add(new Foo(newName));
    }
    else
    {
        // the player is already in the list ...
    }

In this code snippet, we are iterating over all of the items in the list until we find that the player already exists. If no such player exists in your list, it will exit with the value of hasMyItem being false, in which case you will add the new player to the list.

Iterating over all items in a list is a commonly used method and it's definitely good to know. However, you may consider using another data structure called Map<Key, Value>. Map associates a Key with a Value and store them together in the Map as like a list.

You could think Map<Key, Value> as labeling items. Key is a label for each item. Suppose you have a bunch of notebooks on your desk and you want to find a Math note. You can find it without much difficulty if you know the unique label of your math note, such as some texts or images on the cover page. In your example, the Key will be the username, and Value will be the player.

What's good with Map? It provides a simple way to look for Key values you have. The above codes can be more simplified if you use Map.

    Map<String, Foo> map = new HashMap<String, Foo>();

    Foo f1 = new Foo("name1");
    Foo f2 = new Foo("name2");
    Foo f3 = new Foo("name3");

    map.put("name1", f1);
    map.put("name2", f2);
    map.put("name3", f3);

    // will return true and this if statement will be executed
    if (map.containsKey("name1"))
    {
        // will be executed
    }

    // will return false because you don't have and this if statement will not be executed
    if (map.containsKey("some new name"))
    {
        // will not be executed
    }

There are other useful methods provided by Map<K,V>, which can be found here.

As a side note, declare every class member as private whenever you can, rather than default (which is when you don't specify anything) or public. There are many discussions of why you should do that, but basically it's to make protect your own codes safe from other people. You can search on this very easily but here are some links to it. Link1 Link2

I hope this can give you some good starting points.

Community
  • 1
  • 1
Matt
  • 1,424
  • 1
  • 13
  • 17
  • Hay Matthias, thanks for you answer. I tried the first version and it works!! Thank you. Maps sounds interesting but can Value be a Class with many attributes? I would upvote your post if i could :( – MächtigerMatthias Mar 05 '16 at 12:22
  • yes Value can be an class with many attributes. Just define Map playersMap = new HashMap <>(); here your key is name and value is Player. Player.java can have many attributes. Also avoid modifying the List while iterating using For:each. ( http://stackoverflow.com/questions/9806421/concurrentmodificationexception-when-adding-inside-a-foreach-loop-in-arraylist ) – nits.kk Mar 05 '16 at 12:39
  • Yes, both `Key` and `Value` parts can be any `Class` and even `Interface` can be used. When you are declaring your `Map`, you can specify which object types you want to put in each of `Key` and `Value`, and I kind of tried to imply the fact that you could put your own classes in `Value` part by putting a arbitrary class name `Foo` in the map declaration (note the first line). – Matt Mar 05 '16 at 18:16
  • Reasons to put your custom class into value is obvious, because you want to store them. On the other hand, you will sometimes want to put your own classes to the `Key` because then you can further specify when `containsKey()` should return true and when it shouldn't by overriding `equals()` and `hashCode()`, which may be useful in some cases. – Matt Mar 05 '16 at 18:27
1

Since it was pointed out that my use of Set was incorrect, I've decided on another approach (still using the overloaded equals method)

public class Player{
    public String playerName;
    public int Count = 0;
    public Player(String name){
        playerName = name;
    }
    public boolean equals(Player p){
        if(this==p) return true;
        if(this.playerName.equals(p.playerName) return true;
        return false;
}

And

public class mainClass{
    ArrayList playerList;
    public static void main(String[] args){
        playerList = new ArrayList<Player>();
        Player p = new Player("eamplename");
        checkList(p);
    }
    //check Player object against list and add if not exist
    //if desired, the returned boolean can confirm whether or not
    //player was successfully added
    public static boolean checkList(Player player){
        for(Player p : playerList){
            if(p.equals(player)) return false;
        }
        playerList.add(player);
        return true;
}
Calvin P.
  • 1,116
  • 2
  • 8
  • 13
  • Thank you for you answer :) I already found a solution but your idea is amazing. Maybe I will try this when i have to change something again. Thanks Calvin – MächtigerMatthias Mar 05 '16 at 12:34
  • `Set` is an abstract interface, only specific classes implementing this interface can be instantiated. For example `static Set playerList = new HashSet<>()` would be valid. If you want to override the default `equals` method inherited from `java.lang.Object`, the parameters of your overriding method must be the same, in this case `Object` and not `Player` so that objects of another type can be compared as well. Your current `equals` method is considered to be a different method by the compiler and will not be called in the `e1.equals(e2)` operation when adding to the `Set`. – Adrian Sohn Mar 05 '16 at 14:08
  • @AdrianSohn I suspected there may be a few things wrong with my answer. Thank you for pointing it out. I'll stick to what I know for now and revise my answer using a different approach. – Calvin P. Mar 05 '16 at 16:12
  • Glad I could help! Your initial idea by the way of *overriding* the default `equals` behavior for the `Player` class is in my opinion a really good way to go. The `checkList` method in your updated answer does essentially the same thing as the `contains(Object o)` method from the `Collection` interface (iterating through elements until a match is found etc.). You can use this method for example with an `ArrayList` or even a `Set` to check whether a duplicate exists (adding to a `Set` would also work then). – Adrian Sohn Mar 05 '16 at 17:11