Why final variable return without inner class? - java

I want to return final ArrayList in Android, but the ArrayList always return size 0. I do add() in inner class, but the return log faster then inner class log.
My code :
public static ArrayList<SportsData> getSportsFavorite(){
final ArrayList<SportsData> sportsDatas = new ArrayList<>();
DBRequestData reqData = new DBRequestData();
reqData.cmdId = CmdConst.DISCIPLINE_DATA.SELECT_ALL.ordinal();
DisciplineCmd cmd = new DisciplineCmd();
cmd.requestCmd(reqData, new OnDatabaseListener() {
#Override
public void onDBResponse(BaseCmd command) {
if (command == null || command.getResponseData() == null) {
return;
}
ArrayList<DisciplineTable> dbDisciplineList = command.getResponseData().disciplineTableList;
if (dbDisciplineList == null) {
return;
}
if(sportsFavoriteList.size() == 0) {
init();
}
for (DisciplineTable disciplineData : dbDisciplineList){
for (String favoriteCode : sportsFavoriteList){
String[] codeArr = favoriteCode.split("[|]");
String discCode = codeArr[0];
String compeCode = codeArr[1];
if(disciplineData.disciplineCode.equals(discCode) && disciplineData.competitionCode.equals(compeCode)){
int imgRes = SportsUtil.getSportsImgResource(disciplineData.disciplineCode, disciplineData.competitionCode);
sportsDatas.add(new SportsData(imgRes, disciplineData));
Log.e("SportsUtil", "inner Size : "+sportsDatas.size()); // RETURN SECOND -
}
}
}
}
});
Log.e("SportsUtil", "Return Size : "+sportsDatas.size()); //RETURN FIRST
return sportsDatas;
}
Logcat :
07-22 14:33:32.337 651-651/com.samsung.riowow.result E/SportsUtil﹕ Return Size : 0
07-22 14:33:32.347 651-651/com.samsung.riowow.result E/SportsUtil﹕ inner Size : 1
07-22 14:33:32.347 651-651/com.samsung.riowow.result E/SportsUtil﹕ inner Size : 2
07-22 14:33:32.347 651-651/com.samsung.riowow.result E/SportsUtil﹕ inner Size : 3
07-22 14:33:32.347 651-651/com.samsung.riowow.result E/SportsUtil﹕ inner Size : 4
07-22 14:33:32.347 651-651/com.samsung.riowow.result E/SportsUtil﹕ inner Size : 5
The result that want to is ArrayList what size is 5. But always return ArrayList's size is 0. Please help me :) Thanks.
SOLVE
If you want to know reason of this situation, please check the Florian Schaetz's answer.
My solution for this, I change the return type of method and add interface listener parameter. Please check my solution.
First, Create interface and method has parameter you want to return.
public static interface SportsDataListener{
public void onSportsDataResponse(ArrayList<SportsData> sportsDataList);
}
Second, Change method's return type to void and add interface parameter. And call interface's method instead return
public static void getSportsFavorite(final SportsDataListener listener){
final ArrayList<SportsData> sportsDatas = new ArrayList<>();
DBRequestData reqData = new DBRequestData();
reqData.cmdId = CmdConst.DISCIPLINE_DATA.SELECT_ALL.ordinal();
DisciplineCmd cmd = new DisciplineCmd();
cmd.requestCmd(reqData, new OnDatabaseListener() {
#Override
public void onDBResponse(BaseCmd command) {
if (command == null || command.getResponseData() == null) {
return;
}
ArrayList<DisciplineTable> dbDisciplineList = command.getResponseData().disciplineTableList;
if (dbDisciplineList == null) {
return;
}
if(sportsFavoriteList.size() == 0) {
init();
}
for (DisciplineTable disciplineData : dbDisciplineList){
for (String favoriteCode : sportsFavoriteList){
String[] codeArr = favoriteCode.split("[|]");
String discCode = codeArr[0];
String compeCode = codeArr[1];
if(disciplineData.disciplineCode.equals(discCode) && disciplineData.competitionCode.equals(compeCode)){
int imgRes = SportsUtil.getSportsImgResource(disciplineData.disciplineCode, disciplineData.competitionCode);
sportsDatas.add(new SportsData(imgRes, disciplineData));
}
}
}
listener.onSportsDataResponse(sportsDatas);
}
});
}
Last, You can use
SportsUtil.getSportsFavorite(new SportsUtil.SportsDataListener() {
#Override
public void onSportsDataResponse(ArrayList<SportsData> sportsDataList) {
//Some action you want to do. You can use parameter
}
}

Seems pretty asynchronous to me. You are calling a method and give it a callback that will be called AFTER the action is done, here probably after the database returns. The main code isn't blocked, but goes one, while the other OnDatabaseListener waits in the background for an answer, thus your method returns the original list which then suddenly grows as the database answer returns.

I guess your onDBResponse method is running in different thread. You are modifying the arraylist inside that method. So before modifying the arraylist is getting returned in this case. Always it will give you arraylist of size 0.

You should provide a callback interface to getSportsFavorite() which takes the array list as a parameter, and call it on the completion of your OnDatabaseListener method.

Yes the problem is because your onDBResponse() is called after the method has returned the array list. You should suspect this from the order of your logs.
SOLUTION
Assuming that it is your requirement that you get the array list synchronously. Just before your cmd.requestCmd do:
final Object lock = new Object();
then add this before your return sportsDatas;:
synchronized(lock) {
lock.wait();
}
and in the end of onDBResponse() add:
synchronized(lock) {
lock.notify();
}
Essentially, now your method will wait until the response from DB has come before returning the array list.
You will need to catch the InterruptedException and that's it!
Hope it helps! :)

you must run onDBResponse once at least.
public static void main(String[] args) {
final List<String> sportsDatas = new ArrayList<>();
Commond commond = new Commond() {
#Override
public void onDBResponse() {
sportsDatas.add("1");
sportsDatas.add("2");
sportsDatas.add("3");
}
};
System.out.println(sportsDatas.size());
commond.onDBResponse();
System.out.println(sportsDatas.size());
}
}
output:
0
3

Related

SQL IN condition in Java

I have multiple conditions to check as shown below,
if(pouch.getStatus().equals("Finalized") || pouch.getStatus().equals("Ready")
|| pouch.getStatus().equals("Checkout") || pouch.getStatus().equals("Confirmed")
|| pouch.getStatus().equals("Book") || pouch.getStatus().equals("Started")
|| pouch.getStatus().equals("Inital") || pouch.getStatus().equals("Close")) {
// Body Implementation
}
Is there any easy way to check above conditions similar like SQL INcondition, so that code look simpler?
Let's take a look about SQL in features
SQL WHERE IN returns values that match values in a list
So I would use a collection, which implements from Collection<E> and had contains method, make the if statement simpler.
contains(Object o) Returns true if this set contains the specified element.
contains effect is very similar to SQL in.
1.add your multiple conditions in the collection, which implements from Collection<E>
Set<String> dict = new HashSet<String>();
dict.add("Finalized");
dict.add("Ready");
dict.add("Checkout");
dict.add("Confirmed");
dict.add("Book");
dict.add("Started");
dict.add("Inital");
dict.add("Close");
2.using contains to check input value whether exist in the collection.
if (dict.contains(pouch.getStatus()))
{
// do your logic
}
You can use the method matches which is available in String class,
if(pouch.getStatus().matches("Finalized|Ready|Checkout|Confirmed|Book|Started|Inital|Close")){
//your implementation goes here
}
List<String> listOfInputs = new ArrayList<String>();
// add elements in listOfInputs...
boolean isAvailable = listOfInputs.contains(pouch.getStatus());
SQL IN might return more than one result, but in your question, if one condition is satisfied the operation will terminate and return.
You can create an enum to hold all your conditions as shown below.
Assuming your Pouch class is this.
public class Pouch {
private final String status;
public Pouch(final String status) {
this.status = status;
}
public String getStatus() {
return status;
}
}
Here is your enum with the pouch status.
public enum PouchEnum {
Finalized, Ready, Checkout, Confirmed, Book, Started, Inital, Close
}
and check your condition as shown below.
if (PouchEnum.valueOf(pouch.getStatus()) != null) {
// Do some stuff
}
To make it cleaner you can use EnumUtils from apache commons-lang3 this make your code checking more cleaner as shown below.
if (EnumUtils.isValidEnum(PouchEnum.class, pouch.getStatus())) {
// Do some stuff
}
I hope this will help your code to be cleaner.
You can create custom function:
static boolean inCondition(String var, String... ins) {
for (String in : ins) {
if (in.equals(var)) return true;
}
return false;
}
and then use it in this way:
public static void main(String[] args) {
String pouch = "Ready";
if (inCondition(pouch, "Finalized", "Ready", "Checkout" ... )) {
// do something
}
}
Below snippet might help you.
String status = "COMPLETED";
List<String> statusList = new ArrayList<>(Arrays.asList("COMPLETED","INPROGRESS"));
if(statusList.contains(status)){
// do your stuff
}
Using Arrays.asList and then use contains might be the best way at least on my case.
if(Arrays.asList("Finalized", "Ready", "Checkout", "Confirmed",
"Book", "Started", "Inital", "Close").contains(pouch.getStatus())) {
// Body
}
I think if you use the "switch" conditional, the code reads better:
switch (pouch.getStatus()) {
case "Finalized":
case "Ready":
case "Checkout":
case "Confirmed":
case "Book":
case "Started":
case "Inital":
case "Close":
// your code
break;
}
For this particular scenario, I think it's a good candidate for a simple enum like this:
public enum PouchStatus {
FINALIZED, READY, CHECKOUT, CONFIRMED, BOOK, STARTED, INITIAL, CLOSE
}
Usage:
if(PouchStatus.valueOf(pouch.getStatus().toUpperCase()) != null) {
}
You can also move this string sanitizing logic inside a static method in the enum, which would look like this:
public enum PouchStatus {
FINALIZED, READY, CHECKOUT, CONFIRMED, BOOK, STARTED, INITIAL, CLOSE
public static PouchStatus fromDescription(String desc) {
return Arrays.stream(PouchStatus.values()).filter(e -> e.name().equalsIgnoreCase(desc)).findFirst().orElse(null);
}
}
Usage:
if (PouchStatus.fromDescription(pouch.getStatus()) != null) {
}
As a final note, if the Pouch object comes from ORM (e.g.: hibernate/jpa) you can just map these values to the according enum elements right in the entity mapping (pouc.getStatus() would already return a PouchStatus object instead of a String).
Here is full example
public class InConditionJava {
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] arr = { "Finalized", "Ready", "Checkout" };
checkData(arr);
}
private static void checkData(String[] arr) {
Set<String> names = new HashSet<String>(Arrays.asList(arr));
System.out.println("AS Checkout is there in our arr is should return True>>" + names.contains("Checkout")); // true
System.out.println(names.contains("Book")); // false
}
}
Here is another way of initializing List in one line with all statuses, and then checking if the list contains the given status.
// Java 9 way of initializing List with one line
List<String> statuses = List.of("Finalized", "Ready", "Checkout", "Confirmed",
"Book", "Started", "Inital", "Close");
if (statuses.contains(pouch.getStatus())) {
// Body
}
You can create an array of all status, then check if pouch.getStatus() in in that list or not?
public String[] statusArray = new String[]{ "Finalized", "Ready","Checkout","Confirmed", "Book", "Started", "Inital", "Close"};
if( Arrays.asList(statusArray).contains(pouch.getStatus())){
//do something
}
There are already plenty of options here, but you could also use Stream for this task, if the version of the JDK you are using is >= 8:
String status = pouch.getStatus();
if (Stream.of(
"Finalized",
"Ready",
"Checkout",
"Confirmed",
"Book",
"Started",
"Inital",
"Close")
.anyMatch(status::equals)) {
// Body
}
The downside of this method, compared to Collection#contains, is that you must make sure that pouch.getStatus() is not null, otherwise you will get a NullPointerException.

Implemented Iterable hands wrong size back

I'm new to this site, so please feel free to correct me if there's anything wrong about my question or the style of the question.
I need to implement the Iterable Interface in my ShareCollection class, so that I can iterate over all the shares in this class. When I'm testing my class with the sample data it always hands back '0' as size, even though there are (in my example) two shares in my collection.
Here's the code of the class + one sample method which hands back an error:
public class ShareCollection implements Iterable<Share>{
private HashSet<Share> shares;
public ShareCollection() {
this.shares = new HashSet<Share>();
}
public ShareCollection(Collection<Share> shares) {
for (Share s : shares) {
HashSet<Share> checkSet = new HashSet<Share>(shares);
checkSet.remove(s);
if (checkSet.contains(s)) {
throw new IllegalArgumentException("There can't be two shares with the same name!");
}
}
this.shares = new HashSet<Share>(shares);
}
public boolean add(Share share) {
if (share == null) {
throw new NullPointerException("share isnt allowed to be null!");
}
return shares.add(share);
}
#Override
public Iterator<Share> iterator() {
return new HashSet<Share>(shares).iterator();
}
}
Here's the main method with the sample data I'm using:
public static void main(String[] args) {
Share s1 = new Share("s1", new ArrayList<>());
Share s2 = new Share("s2", new ArrayList<>());
ShareCollection sc = new ShareCollection()
sc.add(s1);
sc.add(s2);
int counter = 0;
for (Share s : sc) {
counter++;
}
System.out.print("Counter: " + counter + "\n");
System.out.print("Size: " + sc.size());
}
Here's the output for the main-method:
Counter: 2
Size: 0
Here's the error for the 'add'-method:
java.lang.AssertionError: ShareCollection#size should give 1 for a collection with 1 elements.
Expected: <1>
but: was <0>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at jpp.marketanalysis.tests.data.TestShareCollection.hasElements(TestShareCollection.java:158)
at jpp.marketanalysis.tests.data.TestShareCollection.testAdd(TestShareCollection.java:55)
Thank you in advance for your answers!
Update:
Exchanged the ArrayList with a HashSet (see #SeanPatrickFloyd's first answer)
Possible error: Does your Share class override the .equals() method?
Because ArrayList.contains() delegates to .equals()
Also, I see at least two problems with your code:
An ArrayList is very bad at a .contains() lookup (O(n)). You should use a HashSet instead (in that case you'd need to override both .equals() and .hashCode() in your Share class), it gives you O(1) and handles the .add() method properly for you as well
The Iterator you are returning is the ArrayList's original iterator, which makes your code vulnerable in several ways, including ConcurrentModificationException if you add something while iterating, but also mutation, if someone calls .remove() on the iterator. I'd suggest you make a defensive copy of the collection and use that iterator.
Here's your code rewritten accordingly:
public class ShareCollection implements Iterable<Share>{
private final Set<Share> shares;
public ShareCollection() {
this.shares = new HashSet<>();
}
public ShareCollection(Collection<Share> shares) {
this.shares = new HashSet<>(shares);
}
public boolean add(Share share) {
if (share == null) {
throw new NullPointerException("share isnt allowed to be null!");
}
return shares.add(share);
}
#Override
public Iterator<Share> iterator() {
return new HashSet<>(shares).iterator();
}
}

"Cannot return a value with void result type" error

The following code comes from this answer
try {
// get all the interfaces
List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
//find network interface wlan0
for (NetworkInterface networkInterface : all) {
if (!networkInterface.getName().equalsIgnoreCase("wlan0")) continue;
//get the hardware address (MAC) of the interface
byte[] macBytes = networkInterface.getHardwareAddress();
if (macBytes == null) {
return "";
}
StringBuilder res1 = new StringBuilder();
for (byte b : macBytes) {
//gets the last byte of b
res1.append(Integer.toHexString(b & 0xFF) + ":");
}
if (res1.length() > 0) {
res1.deleteCharAt(res1.length() - 1);
}
return res1.toString();
}
} catch (Exception ex) {
ex.printStackTrace();
}
I get error Cannot return a value with void result type on those 2 lines: return ""; and return res1.toString(); I put the code inside public void onStart() How do I fix this, and can you tell me the cause of this problem?
Instead of returning an empty String, just return;
Methods that are void do not return anything but you can use return statement to terminate an operation if some condition is not met!
I hope this helps!
You need to change the line
public void onStart()
To
public String onStart()
This is because you are returning a String, whereas a void function does not return any data.
If the method cannot be changed to a String return type then you could just put the string into a variable that you declare earlier in the program and then use
return;
To exit the method.
Issue is clear, you are returning a value for a function public void onStart(). You are declaring the return type as void and yet you have return statements.
Try different ways to return the value, like put it in request/session or static variable(not recommanded) etc

Why Synchronization isn't working in the following Code?

This code sometime throwing an Exception even i have used synchronized Method removeFirst within synchronized block of run method, I am adding and removing element on a synchronizedList.
public class NameDropper extends Thread {
private NameList n1;
public NameDropper(List list) {
this.n1 = new NameList(list);
}
public static void main(String[] args) {
List l = Collections.synchronizedList(new LinkedList());
NameDropper n = new NameDropper(l);
n.n1.add("Ozymandias");
Thread[] t = new NameDropper[10];
for (int i = 1; i <= 10; i++) {
t[i - 1] = new NameDropper(l);
t[i - 1].setName("T" + Integer.toString(i - 1));
t[i - 1].start();
}
}
public void run() {
synchronized (this) {
try {
Thread.sleep(50);
String name = n1.removeFirst();
System.out.println(Thread.currentThread().getName() + ": "
+ name);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class NameList {
private List names = null;
public NameList(List list) {
this.names = list;
}
public synchronized void add(String name) {
names.add(name);
}
public synchronized String removeFirst() {
if (names.size() > 0)
return (String) names.remove(0);
else
return null;
}
}
The exception it is throwing:
T1: Ozymandias
T2: null
*Exception in thread "T3" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.entry(Unknown Source)
at java.util.LinkedList.remove(Unknown Source)
at java.util.Collections$SynchronizedList.remove(Unknown Source)
at NameList.removeFirst(NameDropper.java:57)*
T0: null
T8: null
*at NameDropper.run(NameDropper.java:33)*
T6: null
T4: null
T9: null
T7: null
T5: null
You're creating a new NameDropper instance for each thread.
Therefore, the synchronized methods aren't actually locking, since each instance is never used by two threads.
As pointed out by other people, you have a race condition because all of your threads are synchronized on themselves. You need a common object to synchronize on.
I would recommend that you synchronize on the list itself. It will mean that any instances that are contending for the same list are blocked on each other and any threads that are not, will not be blocked. Your add and remove methods should be:
public void add(String name) {
synchronized (name) {
names.add(name);
}
}
public String removeFirst() {
synchronized (name) {
if (names.size() > 0)
return (String) names.remove(0);
else
return null;
}
}
In general:
1) Since you are creating a new instance of your class each time, you basically have no "common" object for all threads to to lock upon. You should define something like:
static final Object lock = new Object();
and synchronize on this object instead.
2) IMHO it's preferable to implement Runnable rather than extending Thread.
Even though you are using Collections.synchronizedList there is a race condition that exists in your code.
Below is the example of the race codition inside your code.
lock(NameDropper[0]) lock(NameDropper[1])
names.size() > 0 is true names.size() > 0 is true
names.remove(0)
names.remove(0) <--- Error here.
Since you are creating NameDropper instance for each thread which shares single instance of List you have this race condition.
What you can do is create separate list for each NameDropper
List l1 = Collections.synchronizedList(new LinkedList());
t[i - 1] = new NameDropper(l1);
This way each NameDropper will have its own instance of List.
As others have stated, NameList is not being shared. Here is one way with minimal recoding to fix your code (there are others):
Change the constructor to take a NameList (not List).
public NameDropper(NameList list) {
this.n1 = list;
}
Create the NameList where you are currently creating the List.
NameList l = new NameList(Collections.synchronizedList(new LinkedList()));

accessing elements of an array which has been passed as a parameter - Java

I have a method which takes an array as a parameter from another class:
public void memPass(Memory[] memLocList) {
memList = memLocList;
for (int i = 0; i < 10; i++) {
System.out.println(memList[i].getSomething());
}
}
-EDIT-
The above prints out 10 values (integers) but if I try the same in the other method with an integer between 0 & 10 I get an NPE.
Can anyone tell me how to access the elements of this array from another method, which also takes in a parameter from another class?
I'm trying to do something along these lines:
public void accessArray(int mem) {
int someInt = memList[mem].getSomething();
}
-EDIT- Sorry, I should add that this gives a NullPointerException.
-NEW EDIT-
OK, I've now edited the code so that all I have in the class is:
public class PLoop {
// instance variable
public Memory[] memlist;
// method 1
public void memPass(Memory[] memLocList) {
memList = memLocList;
System.out.println(memList.length);
}
// method 2
public void accessArray(int mem) {
System.out.println(memList.length);
}
}
The first method prints an integer representing the length of "memList" and the second gives an NPE.
If I'm understanding you right, you want to be able to store memLocList then access it later? If so, I can't see what creating an instance variable wouldn't work.
public class Test {
public Memory[] memlist;
public void memPass(Memory[] memLocList) {
memList = memLocList;
}
public void accessArray(int mem) {
int someInt = memList[mem].getSomething();
}
}
Of course, I don't work in Java enough any more, so it might not be possible to create and assign an instance variable like that. But you could always store the elements in another container.
public class Test {
public List<Memory> memlist;
public void memPass(Memory[] memLocList) {
memlist = new ArrayList<Memory>(Arrays.asList(memLocList));
}
public void accessArray(int mem) {
int someInt = memList.get(mem).getSomething();
}
}
Sorry if I have any syntax errors. But you get the main idea.
If memList is an instance variable of that class and this is the same class in both situations (both methods) then this is obviously a null value at some index of memList.
private static class Memory {
private static int index = 0;
public int getSomething() {
return index++;
}
}
private static class Test {
public Memory[] memlist;
public void memPass(Memory[] memLocList) {
memlist = memLocList;
}
public void accessArray(int mem) {
int someInt = memlist[mem].getSomething();
System.out.println(someInt);
}
}
public static void main(String args[]) {
Test t = new Test();
Memory[] memList = new Memory[4];
memList[0] = new Memory();
memList[1] = null;
t.memPass(memList);
t.accessArray(0);
t.accessArray(0);
t.accessArray(1); //NPE thrown because null value in array
//or
Test t2 = new Test();
t2.accessArray(0); //NPE thrown because array is null (different instance)
}
In your implementation, you are already assuming that the array being passed to the method has 10 elements and that each of these array items has a value, hence, at some point you encounter a NullPointerException. This is dangerous especially when you are just processing an array that is passed as an argument to the method. To ensure that you are only accessing the elements that are available in the array, you need to check what the length of the array is. Also, you need to ensure that whenever you call the methods of an element in an array, (or do anything with it), check first whether it is actually there. For your for loop, you can do something like this:
if (memList != null) {
for (int i = 0; i < memList.length; i++) {
if (memList[i] != null) {
System.out.println(memList[i].getSomething());
}
}
}
That way it is safe from nullpointer exceptions. Using the same concept, you can also apply it to your method like this:
public void accessArray(int mem) {
if (mem > -1 && memList != null && memList.length > mem && memList[mem] != null){
int someInt = memList[mem].getSomething();
}
}
Of course this is assuming that the method with the for loop and the accessArray method are in the same class (or parent-child class) and memList is an instance variable.
And to save the elements of the array as a deep copy of memLocList, you can use what #GJK has suggested which is Arrays.asList to an instance variable and apply the same concept of nullpointer checking that I mentioned above.

Categories

Resources