Won't return object - java

private ArrayList players = new ArrayList<Player>();
public Player getPlayerByName(String theName){
for(int i = 0; i < players.size(); i++){
String pName = (String) players.get(i);
if(pName.equals(theName)){
return (Player) players.get(i);
} else{
return null;
}
}
Above is my code. So, the error comes from this method saying that it must return a Player type yet I am doing so after searching for the matching strings. What do you do for this to work? My apologies if this has been answered already.

There are several issues in the presemted code:
List players should contain Player objects, but in the loop the element of the list is cast to String before comparison, and then the same element is cast to Player.
Only the first element in the list is checked, if it's not matched, a null returned
The code should be fixed like this:
private List<Player> players = new ArrayList<>();
public Player getPlayerByName(String theName) {
for (Player player : players) {
String pName = player.getName();
if (pName.equals(theName)) {
return player;
}
}
return null;
}
It may be worth to use Java Stream for this task:
public Player getPlayerByName(String theName) {
return players.stream() // Stream<Player>
.filter(p -> p.getName().equals(theName)) // keep matched by name
.findFirst() // pick the first match
.orElse(null); // provide null if no match is found
}

As your return statement is inside the for loop, you must have a return statement at the end of the function.
Because when the return statement is inside a conditional statement(or a loop), there is a possibility that the condition is false and the program may never reach the return statement.

Related

Java ArrayList add class object to list if object name is not already in the list?

I have looked through other questions but cant seem to find the answer I am looking for.
I am having trouble figuring out how to create a loop that adds a class object to an ArrayList only if it its name is not used in the list already.
This is the class I have.
package myPackage;
public class Cube {
private int length;
private String name;
public Cube(int initLength, String initName) {
this.length = initLength;
this.name = initName;
}
I would like to create new cubes and add them to a list. Here is the code I am trying to do this with.
In the while loop I can't figure out how to determine if the name has been used or not
package myPackage;
import java.util.ArrayList;
import java.util.Scanner;
public class PartFive {
public static void main(String[] args) {
ArrayList<Cube> cubelist = new ArrayList<>();
Cube oshea = new Cube (13, "oshea");
Cube mike = new Cube (7, "tony");
cubelist.add(oshea);
cubelist.add(mike);
Scanner reader = new Scanner(System.in);
while (true) {
System.out.println("enter cube name (blank quits): ");
String name = reader.nextLine();
if (name.equals("")){
break;
}
System.out.println("enter side length: ");
int length = Integer.valueOf(reader.nextLine());
Cube newcube = new Cube(length, name);
if(cubelist.contains(newcube.name)) {
// dont add to list
}
else {
cubelist.add(newcube);
}
}
reader.close();
System.out.println(cubelist);
}
}
Any constructive criticisms and suggestions are welcomed.
Replace
if(cubelist.contains(newcube.name)) {
dont add to list
}
else {
cubelist.add(newcube);
}
with
boolean found = false;
for(Cube cube: cubelist){
if(cube.getName().equals(name)) {
found = true;
break;
}
}
if(!found) {
cubelist.add(newcube);
}
The idea is to use a boolean variable to track if a cube with the same name as that of the input name already exists in the list. For this, iterate cubelist and if a cube with the same name as that of the input name is found, change the state of the boolean variable and break the loop. If the state of the boolean variable does not change throughout the loop, add the cube to the list.
From the code in your question:
if(cubelist.contains(newcube.name)) {
// don't add to list
}
else {
cubelist.add(newcube);
}
Method contains in class java.utilArrayList is the way to go but you need to be aware that method contains [eventually] calls method equals of its element type. In your case, the element type is Cube. Therefore you need to add a equals method to class Cube. I don't know what determines whether two Cube objects are equal, but I'll guess, according to your question, that they are equal if they have the same name, even when they have different lengths. I will further assume that name cannot be null. Based on those assumptions, here is a equals method. You should add this method to class Cube.
public boolean equals(Object obj) {
boolean areEqual = false;
if (this == obj) {
areEqual = true;
}
else {
if (obj instanceof Cube) {
Cube other = (Cube) obj;
areEqual = name.equals(other.name);
}
}
return areEqual;
}
Now, in method main of class PartFive you can use the following if to add a Cube to the list.
if (!cubelist.contains(newcube)) {
cubelist.add(newcube);
}
You can check for duplicate names in the cubelist array using lambda expressions (for better readability):
boolean isNameAlreadyExisting = cubelist.stream()
.anyMatch(cube -> cube.getName().equals(newcube.getName())); // this is returning true if any of the cubelist element's name is equal with the newcube's name, meaning that the name is already existing in the cubelist
if (!isNameAlreadyExisting) {
cubelist.add(newcube);
}
One thing that you should do is to remove the while(true) instruction which causes an infinite loop.
Another suggestion is to display the name of objects contained by cubelist, to see that indeed the names are not duplicated:
cubelist.stream()
.map(Cube::getName)
.forEach(System.out::println);

Identify a unique String

I have some strings read in from a file that look like this
"Anderson, T",CWS,SS,...
"Anderson, B",MIA,3B,...
"Galvis, F",CIN,SS,...
I need the user to input a name (such as "Anderson" or "Galvis") and if the name is insufficient to identify a unique player I need to print an error message.
So if the user wants to pick "Anderson, T" they would have to specify "Anderson, T").
Currently I have a function that takes in the name ("Anderson, T" or "Anderson, B") and it finds the correct string, the function can be found below
public static boolean findPlayer(String playerName) {
// Find specified player
int found = -1;
for (int j = 0; j < players.size(); j++) {
if (players.get(j).toString().toLowerCase().contains(playerName.toLowerCase())) {
found = 0;
break;
}
}
if (found == 0)
return true;
else
return false;
}
Is there a way for me to modify the code so that it takes in "Anderson" and then print out an error?
Since the method is named findPlayer, it should return the found player.
Since you want it to fail if there are multiple player matching the name, you could use an exception to indicate that.
You obviously want to know if no player is found, so you can return null, or change return type to Optional, or throw another exception to indicate that.
Here we'll go with exception for non-unique name, and null for not found:
public static Player findPlayer(String playerName) {
Pattern nameRegex = Pattern.compile(Pattern.quote(playerName), Pattern.CASE_INSENSITIVE);
Player foundPlayer = null;
for (Player player : players) {
if (nameRegex.matcher(player.toString()).find()) {
if (foundPlayer != null)
throw new IllegalArgumentException("Multiple player matches name: " + playerName);
foundPlayer = player;
}
}
return foundPlayer; // returns null if not found
}
Changed code to use regex for case-insensitive contains logic, so it doesn't create a lot of intermediate lower-case strings during the search.

My linked list isn't returning the proper values or updating a list properly

When my program comes to this method it never seems to update the target value. If I input "dave" it will remain "dave" no matter how many calls to the method are made.
public Person lookup(String name){
if(firstPerson == null){
return null;
}
Person target = null;
for (target = firstPerson; target != null; target = target.nextPerson){
if(name.equals(target.name)){
return target;
}
else {
return null;
}
}
return target; // replace this line
}
If I add a friend via this addFriend method firstFriend will end up printing whatever the last added name was. If the inputted named were rob bill and travis
The output would be travis travis travis.
public void addFriend(Person friend){
firstFriend = new Friend(friend, firstFriend);
return; // replace this line
public String friendString(){
String friendList = "";
if(firstFriend == null){
return null;
}
for(Friend pointer = firstFriend; pointer != null; pointer = pointer.nextFriend){
friendList = friendList + firstFriend.who.name + " ";
}
return friendList.trim(); // replace this line
}
You always return in the first iteration of the loop. If the person is found it's returned (the if branch), and if it isn't, null is returned (the else branch). Instead, you should keep iterating until you find the correct person or exhaust the list. The first condition, BTW, is a subset of the loop (if firstPerson is null target will just become null immediately), and can (should!) also be removed:
public Person lookup(String name){
Person target = null;
for (target = firstPerson; target != null; target = target.nextPerson) {
if (name.equals(target.name)) {
return target;
}
}
return target; // Or null explicitly - matter of taste.
}
if(name.equals(target.name)){
return target;
}
else {
return null;
}
The else part needs to go away. The effect of this code is that it only checks the first value and if it is not the value that you want to look up it is coming out straight away.
Change
return target; // replace this line
to return null;
and remove the else part mentioned above

Using for : each loop to return multiple Strings nestled in an ArrayList

I'm trying to return all of the 'players and their goals' in a sports team using the following:
public String printPlayers(){
for (Player player : this.players){
return player.toString();
}
}
Netbeans says there is no return statement, which I presume is because it is within the for-each loop. But if I place it outside it will only return one item. Here is the test code:
Team barcelona = new Team("FC Barcelona");
Player brian = new Player("Brian");
Player pekka = new Player("Pekka", 39);
barcelona.addPlayer(brian);
barcelona.addPlayer(pekka);
barcelona.addPlayer(new Player("Mikael", 1));
barcelona.printPlayers();
In the Player Object, here is what toString does:
public String toString(){
return ("Player: "+this.name+", goals "+this.goals);
}
Java allows you to return only a single object. It is not possible to return multiple objects. If you want to return multiple objects from a single method, you first have to collect them into a single object, for example an array, a List or a String, and then return that.
Let's look at your code. Netbeans complains about the missing return statement because it is possible that your players collection is empty. In that case the loop block is never executed and the method end without a return statement, which is not allowed. So let's repair your method as follows:
public String printPlayers(){
for (Player player : this.players){
return player.toString();
}
return "";
}
Also now the method only returns a single object: it will convert the first player in your collection to a string and then return that. The other players are ignored. So you have to collect your players in a single object. Since you want to return a string, it makes sense to collect the strings in a single string:
public String printPlayers(){
String result = "";
for (Player player : this.players){
result += " " + player.toString();
}
return result;
}
Now you can try to make the result better, for example by removing the leading space for the first element, or by adding commas instead of spaces, etc. Also, for more performance you can use a StringBuilder for building your string (but think about performance once you have a working method!).
public String printPlayers(){
String data="";
for (Player player : this.players){
data +=player.toString();
}
return data;
}
Use a StringBuilder
public String printPlayers(){
StringBuilder sb = new StringBuilder();
for (Player player : this.players){
sb.append(player.toString());
}
return sb.toString();
}
Why netbeans complaining is, what if you not enter to for loop ?? So there should be a return always.
Coming to actual problem,
Just build a String and return
public String printPlayers(){
StringBuilder builder=new StringBuilder();
for (Player player : this.players){
builder.append(player).append(" ");
}
return builder.toString();
}
That's build a String with appending all players as String and return finally.

Searching a class array with multiple values per record

I need to search an object array for a Name and then print out all info corresponding to that name.
I have
public class AccessFriendlyFile {
private Friendlies[] fr = new Friendlies[100];
private int size = 0;
public AccessFriendlyFile (){
try {
Scanner scFile = new Scanner(new File("Friends.txt"));
String line, name, surname, cell, mail, landline;
while (scFile.hasNext()){
line = scFile.nextLine();
Scanner sc = new Scanner(line).useDelimiter("#");
name = sc.next();
surname = sc.next();
cell = sc.next();
if (sc.hasNext()){
mail = sc.next();
landline= sc.next();
fr[size] = new ExtendFriendlies(name, surname, cell, mail, landline);
}
else {
fr[size]= new Friendlies(name, surname, cell);
}
size++;
sc.close();
}
}catch (FileNotFoundException ex){
System.out.println("File not found");
}
How do I code a method that will search "fr" for a name and print out all corresponding info?
Many Thanks
Jesse
Edit:
Here is my Search method, that is currently not working.
public int Search(String name) {
int loop = 0;
int pos = -1;
boolean found = false;
while (found == false) {
if (fr[loop] == name) {
found = true;
pos = loop;
} else {
loop++;
}
}
return pos;
}
Incomparable types error on the if statement.
In your Friendlies class, have a method called getName() that will return the name of that Friendly. Iterate through the fr until you find the matching name. Once you've found that name, use similar get methods to print out all the information you want for the matching Friendly you just found.
I would suggest that you rename your variables here. The Friendlies class stores, I think, a single contact, a Friend. The list of Friend objects is an array that you might beter name friendList or even friendlies. I would also encourage you to not use size as a counter variable. Size is how many friends you have, and you can iterate through them using i, or friendCounter, or use a for each loop as I demonstrate below,
public Friendlies find(String name) {
for(Friendlies friend : fr) {
if(friend.getName().equalsIgnoreCase(name))
return fiend;
}
return null;
}
//now to print the info you can do this:
Friendlies findJoe = find("Joe");
if(findJoe==null)
System.out.println("You have no friends namd Joe.");
else
System.out.println(findJoe);
My code assumes that you implement toString() in Friendlies. If you use netbeans, you can auto-generate this code and then tweak it to get the format you want. (Just right-click where you want to write the method and choose insert code)
This should work:
public List<Friendlies> search(String name) {
List<Friendlies> list = new ArrayList<Friendlies>();
for(Friendlies friendlies : fr) {
if(friendlies.getName().equals(name)) {
list.add(friendlies);
}
}
return list;
}
Then, with the returned list, implement a nice display of the data :)
Assuming the AccessFriendlyFile loads the data into your array, you can use a for each loop, if you want to retieve all the matching names :
List<Friendlies> getByName(String searched){
List<Friendlies> result = new Arraylist<Friendlies>();
for (Friendlies currentFriendly : fr){
if (searched.equalsIgnoreCase(currentFriendly.getName()){
result.add(currentFriendly);
}
}
return result;
}
for only the first one :
Friendlies getByName(String searched){
for (Friendlies currentFriendly : fr){
if (searched.equalsIgnoreCase(currentFriendly.getName()){
return currentFriendly;
}
}
return null;
}
You should use lists instead of fixed arrays. If the files contains more than 100 records you'll get an indexoutofbounds exception.

Categories

Resources