Check if an element of array is Empty - java

My method applyBonus() from the class BonusEmporium gets bonus objects from the arrayList of City objects and applies them to a Player object.
when i write my function like this i have no problem testing it:
public class BonusEmporium extends Bonus {
public BonusEmporium(int cities) {
this.setBonusType(BonusType.EMPORIUM);
this.cities=cities;
setCity(new ArrayList<City>(cities));
}
public void applyBonus(Player player){
Bonus bonus=getCity().get(0).getBonus().get(0);//gets the first bonus from the first
//city
bonus.applyBonus(player);
Bonus bonus=getCity().get(0).getBonus().get(1);//gets the second bonus from the first
//city
bonus.applyBonus(player);
Bonus bonus=getCity().get(1).getBonus().get(0);//gets the first bonus from the
//second city
bonus.applyBonus(player);
}
}
The problem is when i want to run it only while the arraylists contain elements, how do i check that an element from an array is empty?
public class BonusEmporium extends Bonus {
public BonusEmporium(int cities) {
this.setBonusType(BonusType.EMPORIUM);
this.cities=cities;
setCity(new ArrayList<City>(cities));
}
public void applyBonus(Player player){
int i=0,j=0;
while(j<cities){
while(getCity().get(j).getBonus().get(i)!=null){//In theory this should
//verify that the element bonus i from the city j is not empty
//but i get NullPointerException
Bonus bonus=getCity().get(j).getBonus().get(i);
bonus.applyBonus(player);
i++;
}
j++;
}
}
}

It's difficult to tell what you are asking, but you should be able to avoid the error by handling the message chain better.
public void applyBonus(Player player){
List<City> cities = getCity();
for(int i = 0; cities != null && i < cities.size(); i++){
City c = cities.get(i);
List<Bonus> bonuses = c.getBonus();
for (int j = 0; bonuses != null && j < bonuses.size(); j++) {
Bonus b = bonuses.get(j);
if (b != null)
b.applyBonus(player);
}
}
}

You check if the element is empty like this:
if(array != null && array.get(index) == null) // element is null when empty
To check if the array as a whole is empty (has no elements):
if(array != null && array.isEmpty())

In general the problem in java is chaining getters like this:
getCity().get(j).getBonus().get(i)!=null
You can get nullpointer exception from 4 places here. You can check them all like:
if (getCity()!=null &&
getCity().get(j) &&
getCity().get(j).getBonus() &&
getCity().get(j).getBonus().get(i)!=null){
....
}
Other way could be encapsulating whole code in try - catch and catching NPE, which is more like hack.
I also suggest using foreach instead while and don't store array size in separate variables, because you can always get it using
myArr.getSize()
And also check javadoc about ArrayList constructor:
new ArrayList<City>(cities)
because this is likely not doing what you expect
Short story:
init all ArrayLists in constructor (don't specify size)
use foreach loops
don't put nulls into the arrays
and you should be fine without checking for empty elements

Related

How to count the nested list elements size using Java 7?

I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}

find and return an element of an array in java

So I've been trying to figure this out on my own for the past couple of hours but I'm stuck.
I have an array that has a list of a person's name, age, height (in cm). I want to create a method where I use only the person's name as a parameter and searches for the name in the array; if there is no matching name, return null.
Looks like this:
data = new data[50];
data[0] = new data("Dan", 23, 179);
data[1] = new data("David", 20, 180);
data[2] = new data("Sharon", 19, 162);
data[3] = new data("Jessica", 22, 160);
data[4] = new data("Nancy", 25, 164);
...
numberData = 30; // this is the number of people that are in this array so far
This is what I've been trying so far..
public data findData(String name) {
for (int i = 0; i < numberData; i++) {
if (name == data[i]) {
return data[i];
} else {
return null;
}
}
}
I know it isn't right, but I can't seem to find a solution. Any ideas?
array is referencing the Data class with name parameter so we should compare with name parameter not directly with reference of data and for string comparisons always go for equals() method.
public Data findData(String name) {
for (int i = 0; i < numberData; i++) {
if (name.equals(data[i].getName())) {
return data[i];
}
}
return null;
}
Since you want to compare strings you must use the equals method.
Here's an example of how can you use java 8:
public Data findData(Data[] datas, String name) {
return Arrays.stream(datas).filter(data -> data.getName().equals(name)).findAny().orElse(null);
}
In case the loop doesn't execute at least once, you're missing return value.
== compares references, equals compares Strings.
Return null just in case, there is no such element in the array.
Class names should start with a capital letter. Please write Data instead of data.
Code:
public Data findData(String name) {
for (Data d : data) {
if (name.equals(d.getName())) {
return d;
}
}
return null;
}
is what you're looking for. In the original code, null was returned if the 0th element wasn't name.
OK, the above was a quick fix and now some theory:
The pseudo code for linear search in an array:
Loop through all elements in an array. If any matches with the one you're looking for, return it.
If nothing was returned, return the indicating value (null in our case).
Look, in the original code, on the 0th element, you decided whether to return that element or a null. Also, if the loop wasn't run at least once, there was no return statement to hit.
Use equals() to compare strings,
e.g.
if(name.equals(data[i].getName())) {
statements...
}
You should use equals() to compare strings. equals() checks the actual contents of the string, == checks if the object references are equal.
And also, as mentioned above, move return null outside the loop;
You can use following code. Assuming that your data class will have getName() method which returns the name value.
public data findData(String name) {
for (int i = 0; i < numberData; i++) {
if (name.equals(data[i].getName())) {
return data[i];
}
}
return null;
}
move the return null statement out of the loop.
Oh! and yes, use the equals() method instead of ==

Removing specific items in Arraylist

I am struggling with removing items from my arraylist. More specifically, I have two arraylists, being persons and vulcanos. Both are located in a grid. Each time step, people can move or not (this happens randomly, to the adjecant cells), while volcanos are static during the whole simulation. Volcanos can erupt or not. This is determined by a probability defined by the user. When at a certain timestep a person is located at the same cell as an erupting volcano, this person dies. But I don't know how I can remove that specific person from my array. So far I got the following (is repeated for each time step).
for (int j = 0; j < persons.size(); j++) {
for (int k = 0; k < volcanos.size(); k++) {
if ((persons.get(j).getXCoordPerson()) == (volcanos.get(k).getXCoordVolcano())
&& (persons.get(j).getYCoordPerson()) == (volcanos.get(k).getYCoordVolcano())
&& (volcanos.get(k).getEruptionStatus() == true)) {
// all persons being on the same cell as an erupting volcano die
}
}
}
You can do this with an Iterator too:
for(Iterator<Person> personIterator = persons.iterator(); i.hasNext(); ) {
Person person = personIterator.next();
for(Volcano volcano : volcanos) {
if(volcano.getEruptionStatus() &&
volcano.getYCoordVolcano() == person.getYCoordPerson() &&
volcano.getXCoordVolcano() == person.getXCoordPerson()) {
personIterator.remove();
}
}
}
In this case, you are using the iterator to do the removing, leaving the ArrayList in the state you want as a side effect of the loops.
One thing to watch out for is that you do not modify the list of people during this loop or you will end up with a ConcurrentModificationException. I'm assuming you have one single thread operating, and that this is for schoolwork or something similar. If you were doing this in the real-world, you would have to account for the fact that both lists (people and volcanos) could be changing at any time.
Try to mark your people as dead or harmed(etc.) or add them to another list. Then delete them after loop like
persons.removeAll(deadPeople);
If you don't mind working with Iterable instead of List, and if you don't mind taking dependency on Guava, then why not use Iterables?
Iterable<Person> filtered = Iterables.filter(persons, new Predicate<Person>() {
#Override
public boolean apply(Person person) {
for (Volcano v : volcanos) {
if (v.getEruptionStatus() &&
v.getXCoordVolcano() == person.getXCoordPerson() &&
v.getYCoordVolcano() == person.getYCoordPerson()) {
return false;
}
}
return true;
}
});
This will filter out all dead Persons, and will leave filtered with only living people

Comparing With an ArrayList

My program calls for being able to delete a name and number from a phone book. I have gotten the deleting to work but it only deletes the index from the ArrayList that the text box corresponds to. I need to be able to delete both the name and the number from their respective arraylists by entering it into either texbox. Sorry if there is another answer to this i guess i dont really know how to word it correctly. My code is below.
ArrayList<String> Names = new ArrayList<String>();
ArrayList<String> Numbers = new ArrayList<String>();
if(e.getSource() == DeleteBtn)
{
if (NameTxt.getText() != null)
{
for( int i=0; i<= NamesList.size(); i++)
{
if(NamesList.contains(NameTxt.getText()))
{
NamesList.remove(i);
System.out.println(NamesList.size());
}
}
}
if (PhoneTxt.getText() != null)
{
for( int i=0; i<= NumbersList.size(); i++)
{
if(NumbersList.contains(PhoneTxt.getText()))
{
NumbersList.remove(i);
System.out.println(NumbersList.size());
}
}
}
}
If you HAVE to use ArrayLists then you might consider using an ArrayList of pairs.
You can create your own class, say PhoneBookEntry.
class PhoneBookEntry {
String _name;
String _phone;
// etc...
}
ArrayList<PhoneBookEntry>
Consider using a HashMap instead of the ArrayLists.
HashMap<String, String> numbersAndNames = new HashMap<String, String>();
numbersAndNames.put("John", "123 456 789");
If I were you, I would reconsider my logic. I'm going to try and avoid posting code for you to keep from giving you the answer/doing the work for you but...
I only see you modifying the NamesList variable. You aren't modifying the Names or Numbers ArrayList variables.
I would put your 'contains if statement' some place else. Your checking to see if NameList contains NameText a bunch of times. I don't see why you would need to check it more than once.
If you want to get smart, you can do away with the array completely and just use the getIndex() method to some effect in java...which gets the index corresponding to NameText (I'm being vague here deliberately, so think about what I'm saying).
You can use a HashMap if you want, but it's not necessary.
Per suggestion of using an additional class to track the name/number combo.
ArrayList contacts = new ArrayList();
if(e.getSource() == DeleteBtn) {
if (NameTxt.getText() != null) {
for( int i=0; i<= contacts.size(); i++) {
if(contacts.getName().contains(NameTxt.getText())) {
contacts.remove(i);
System.out.println(contacts.size());
}
}
}
public class PhoneContact {
private String name;
private String number;
/*
Getters and Setters
*/
}
First of all, NumbersList.contains(PhoneTxt.getText()) returns if PhoneTxt.getText() is anywhere in the list.
What you want to check is the NumbersList.get(i).equals(PhoneTxt.getText()) note that i used equals() instead of == operator
my friend actually found the answer, he simply added the other ArrayList(i), thank you to all who posted answers, as they gave me food for thought, just thought the logic of the answer would not work but i was proven wrong, here is the code for anyone interested.
if(e.getSource() == DeleteBtn)
{
if (NameTxt.getText() != null)
{
for( int i=0; i<= NamesList.size(); i++)
{
if(NamesList.contains(NameTxt.getText()))
{
NamesList.remove(i);
NamesList.remove(i);
System.out.println(NamesList.size());
System.out.println(NumbersList.size());
}
}
}
if (PhoneTxt.getText() != null)
{
for( int i=0; i<= NumbersList.size(); i++)
{
if(NumbersList.contains(PhoneTxt.getText()))
{
NumbersList.remove(i);
NamesList.remove(i);
System.out.println(NamesList.size());
System.out.println(NumbersList.size());
}
}
}
}

Is this proper use of storing values into an array via getText()?

In my Java program's constructor I have the following:
thirdRow.add(button);
button.setActionCommand("Sumbit");
button.addActionListener(this);
And here is the corresponding actionPerformed method that's supposed to take 3 values from some textfields and store them into arrays:
public void actionPerformed(ActionEvent e)
{
String arg = e.getActionCommand();
if (arg == "Submit")
{
//enlarge arrays
qtyStr = enlargeArray(qtyStr);
typeStr = enlargeArray(typeStr);
colorStr = enlargeArray(colorStr);
//add from textfields into current
qtyStr[qtyStr.length-1] = qty.getText();
typeStr[typeStr.length-1] = type.getText();
colorStr[colorStr.length-1] = color.getText();
}
}
//method to enlarge an array by 1
public String[] enlargeArray(String[] currentArray)
{
String[] newArray = new String[currentArray.length + 1];
for (int i = 0; i<currentArray.length; i++)
newArray[i] = currentArray[i];
return newArray;
}
When I run the application, populate the textfields, and click the submit button nothing happens. How can I verify that my string arrays are being appended like they're supposed to?
You've a problem here: if (arg == "Submit")
Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
Also, for safety's sake, I try to use String constants wherever possible so as not to be tripped up by misspellings.
If you want to do your code this way, I would probably do two things:
1) maintain index fields for each array for the next free index, and
2) I wouldn't recommend resizing your array by 1 each time, as our current code is running through the array 2 n times (n = array length), 1st to initialize the array, and 2nd to create a new array.
Two options to optimize thisL one would be be to look into the Arrays class. it contains methods such as Array.copyOf() that can perhaps be useful here. You could also check if the array is full, and if it is then resize it by a number greater than one to reduce extra work.
For instance:
import java.util.Arrays;
class Test{
private String[] a;
private int next;
public Test(int size){
a = new String[size];
next = 0;
}
public void add(String s){
if(next == a.length){
Arrays.copyOf(a, a.length+1);
}
a[next] = s;
next++;
}
}
The easiest way would be to use an ArrayList (or any class that implements the java.util.List interface), as previously mentioned by Jon Skeet - it will do all the work for you.

Categories

Resources