Why aren't my variables pointing to the same array? - java

I have two classes. One that has the array (ArrayStorage) and the other (ArrayConsumer) has just a variable that will act as a simple reference to an array.
I add a new element to the array using $my_array. Then I check to see if the new element is visible in the $obtained_array. But the test fails because it cannot find the new element. They act like they were different arrays. Shouldn't they point to the same array?
public function testArrayMadness() {
$arrayStorage = new ArrayStorage();
$my_array = $arrayStorage->getArray();
$arrayConsumer = new ArrayConsumer($my_array);
$obtained_array = $arrayConsumer->getArray();
$my_array[3]='c';
$this->assertContains('c', $obtained_array);
}
}
class ArrayStorage {
private $my_array=[1=>'a',2=>'b'];
function getArray() { return $this->my_array; }
}
class ArrayConsumer {
private $obtained_array;
function __construct($array) { $this->obtained_array=$array; }
function getArray() { return $this->obtained_array; }
}
Update:
I did the same on test in Java, it gives me an indexOutOfBoundsException. Does that mean both php and java works the same way in this aspect or is there something wrong with my code?
#Test
public void testArrayMadness() {
ArrayStorage arrayStorage = new ArrayStorage();
List<String> my_list = arrayStorage.getList();
ArrayConsumer arrayConsumer = new ArrayConsumer(my_list);
List<String> obtained_array = arrayConsumer.getList();
my_list.add("c");
assertEquals("c", obtained_array.get(3));
}
}
class ArrayStorage {
private List<String> my_list;
public ArrayStorage() {
my_list = new ArrayList<>();
my_list.add("a");
my_list.add("b");
}
public List<String> getList() { return my_list; }
}
class ArrayConsumer {
private List<String> obtained_list;
public ArrayConsumer(List<String> list) {
this.obtained_list = list;
}
public List<String> getList() { return this.obtained_list; }
}

PHP arrays are not objects, they are assigned by value:
$a = [1,2,3];
$b = $a;
$b[2] = 99;
print_r($b); // 1,2,99
print_r($a); // 1,2,3
A workaround is to use reference signs & (a bad idea generally) or ArrayObjects:
$a = new ArrayObject([1,2,3]);
$b = $a;
$b[2] = 99;
print_r($b); // 1,2,99
print_r($a); // 1,2,99

return reference array using & operator
something like return &$this->my_array;

Related

Combining ArrayList<String> and ArrayList<Integer> into One Adapter and List View

ArrayList<String> stepsList = new ArrayList<>();
ArrayList<Integer> stepsPosList = new ArrayList<>();
stepsAdapter = new ArrayAdapter<String>(this,R.layout.steps_item,R.id.etStepsDetails,stepsList);
stepsAdapter2 = new ArrayAdapter<Integer>(this,R.layout.steps_item,R.id.tvStepsPosition,stepsPosList);
stepsView.setAdapter(stepsAdapter);
stepsView2.setAdapter(stepsAdapter2);
Is it possible to combine the 2 array adapter into 1? The layout is on the same page but I need 2 id and 2 array list into each. and then call the list view.
POJO CLASS
public class CombineData {
ArrayList<String> stepsList;
ArrayList<Integer> stepsPosList;
public CombineData(ArrayList<String> stepsList,ArrayList<Integer> stepsPosList){
this.stepsList = stepsList;
this.stepsPosList = stepsPosList;
}
public CombineData(){
}
public ArrayList<String> getStepsList() {
return stepsList;
}
public void setStepsList(ArrayList<String> stepsList) {
this.stepsList = stepsList;
}
public ArrayList<Integer> getStepsPosList() {
return stepsPosList;
}
public void setStepsPosList(ArrayList<Integer> stepsPosList) {
this.stepsPosList = stepsPosList;
}
}
THIS LINE SHOWS AN ERROR : CANNOT RESOLVE CONSTRUCTOR ARRAYADAPTER... int,int,ArrayList
stepsAdapter = new ArrayAdapter<CombineData>(this,R.layout.steps_item,R.id.etStepsDetails,stepsList);
you should make POJO class
class CombineData(
ArrayList<String> stepsList,
ArrayList<Integer> stepsPosList
)
{
getter()/setter()
}
then change adapter
stepsAdapter = new ArrayAdapter<CombineData>(this,R.layout.steps_item,R.id.etStepsDetails,stepsList);
Now, you can access in the listview like this
item.stepsList
item.stepsPosList

How to read MultiValue ArrayList in Java

I've defined a arrayList as following
List<List<RiskyPersons>> dataArray = new ArrayList<>();
Here is RiskyPersons Class
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
Then I've successfully added data and saved in dataArray ArrayList.
Following output is showing the saved ArrayList using SOP(dataArray);
[[RiskyPersons{sa3tenant=Homeless.SA3Tenant#3a7cc6b0, NumberofPersonInCategory=99}]]
I want to read this dataArray ArrayList and display values separately. How do I access "NumberofPersonInCategory" value?
From Java-8 and above one can use stream:
dataArray.stream()
.flatMap(List::stream)
.map(RiskyPersons::NumberofPersonInCategory)
.forEach(System.out::println)
I hope this will help you !
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public int getNumberofPersonInCategory() {
return NumberofPersonInCategory;
}
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
List<Integer> values = dataArray.parallelStream().flatMap(Collection::stream).map(RiskyPersons::getNumberofPersonInCategory)
.collect(Collectors.toCollection(ArrayList::new));
You'll need to iterate it twice as
for (List<RiskyPersons> rp : dataArray) {
for (RiskyPersons o : rp) {
System.out.println(o.NumberofPersonInCategory); // unrelated : but its bad naming convention
}
}

EasyMock: How to Verify Method Order for Set of Values Where Order of Set Does Not Matter

I have a test in which I have a set of specific values for which two different methods will execute once for each value in the set. I need to check that the two methods are called in a specific order in relation to each other, but not in relation to the order of the set of values. For example:
String[] values = { "A", "B", "C" };
for (...<loop over values...) {
methodOne(value);
methodTwo(value);
}
It does not matter which order values is in, but I need to verify that methodOne() and methodTwo() are called for each value in the set AND that methodOne() is always called before methodTwo().
I know that I can create a control and expect methodOne() and methodTwo() for each value, then do control.verify(), but this depends on values being in a specific order.
Is there an elegant way to do this?
Thanks
You can do this using andAnswer().
Basically, inside the andAnswer() from methodOne() you set some variable to hold what the passed in value was.
Then in the andAnswer() for methodTwo() you assert that the same argument matches what you saved from your methodOne answer.
Since each call to methodOne will modify this variable it will make sure methodTwo() is always called after methodOne().
Note this solution is not thread safe
First you need something to hold the variable from the methodOne call. This can be a simple class with a single field or even an array of one element. You need this wrapper object because you need to reference it in the IAnswer which requires a final or effectively final field.
private class CurrentValue{
private String methodOneArg;
}
Now your expectations. Here I called the class that you are testing (The System Under Test) sut:
String[] values = new String[]{"A", "B", "C"};
final CurrentValue currentValue = new CurrentValue();
sut.methodOne(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
//save the parameter passed in to our holder object
currentValue.methodOneArg =(String) EasyMock.getCurrentArguments()[0];
return null;
}
}).times(values.length); // do this once for every element in values
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
//check to make sure the parameter matches the
//the most recent call to methodOne()
assertEquals(currentValue.methodOneArg, value);
return null;
}
}).times(values.length); // do this once for every element in values
replay(sut);
... //do your test
verify(sut);
EDIT
you are correct that if you are using EasyMock 2.4 + you can use the new Capture class to get the argument value in a cleaner way for methodOne(). However, you may still need to use the andAnswer() for methodTwo() to make sure the correct values are called in order.
Here is the same code using Capture
Capture<String> captureArg = new Capture<>();
sut.methodOne(and(capture(captureArg), isA(String.class)));
expectLastCall().times(values.length);
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
assertEquals(captureArg.getValue(), value);
return null;
}
}).times(values.length);
replay(sut);
For those interested, I solved this issue using intended EasyMock functionality. The solution was to make a custom IArgumentMatcher to verify against a collection of values and to enforce how many times each value is matched consecutively. The custom matcher, in addition to using strict mocking exactly solves the original problem.
public class SetMatcher implements IArgumentMatcher {
private List<String> valuesToMatch;
private List<String> remainingValues;
private String currentValue = null;
private int timesMatched = 0;
private int setMatches;
public SetMatcher(final List<String> valuesToMatch, final int times) {
this.valuesToMatch = new ArrayList<String>(valuesToMatch);
this.remainingValues = new ArrayList<String>(valuesToMatch);
this.setMatches = times;
}
public String use() {
EasyMock.reportMatcher(this);
return null;
}
public void appendTo(StringBuffer buffer) {
if (this.remainingValues.size() == 0) {
buffer.append("all values in " + this.valuesToMatch + " already matched " + this.setMatches + " time(s)");
} else {
buffer.append("match " + this.valuesToMatch + " " + this.setMatches + " time(s) each");
}
}
public boolean matches(Object other) {
if (this.timesMatched >= this.setMatches) {
this.currentValue = null;
this.timesMatched = 0;
}
if (null == this.currentValue) {
if (this.remainingValues.contains(other)) {
this.currentValue = (String) other;
this.timesMatched = 1;
this.remainingValues.remove(other);
return true;
}
} else if (this.currentValue.equals(other)) {
this.timesMatched++;
return true;
}
return false;
}
}
The class being tested:
public class DataProcessor {
private ServiceOne serviceOne;
private ServiceTwo serviceTwo;
public DataProcessor(ServiceOne serviceOne, ServiceTwo serviceTwo) {
this.serviceOne = serviceOne;
this.serviceTwo = serviceTwo;
}
public void processAll(List<String> allValues) {
List<String> copy = new ArrayList<String>(allValues);
for (String value : copy) {
this.serviceOne.preProcessData(value);
this.serviceTwo.completeTransaction(value);
}
}
}
And the test:
public class DataProcessorTest {
List<String> TEST_VALUES = Arrays.asList("One", "Two", "Three", "Four", "Five");
#Test
public void test() {
IMocksControl control = EasyMock.createStrictControl();
ServiceOne serviceOne = control.createMock(ServiceOne.class);
ServiceTwo serviceTwo = control.createMock(ServiceTwo.class);
SetMatcher matcher = new SetMatcher(TEST_VALUES, 2);
for (int i = 0; i < TEST_VALUES.size(); i++) {
serviceOne.preProcessData(matcher.use());
serviceTwo.completeTransaction(matcher.use());
}
control.replay();
DataProcessor dataProcessor = new DataProcessor(serviceOne, serviceTwo);
dataProcessor.processAll(TEST_VALUES);
control.verify();
}
}
The test will fail for any of the following:
ServiceOne and ServiceTwo are called in the wrong order
ServiceOne and ServiceTwo are not called consecutively with the same value
ServiceOne or ServiceTwo are called with a value that is not in the specified value list
A call is made beyond the number of expected times for a value in the list

Getter and setter for List

class MipRequest{
private List<String> MipIDs=null;
public List<String> getMipIDs() {
return MipIDs;
}
public void setMipIDs(List<String> mipIDs) {
MipIDs = mipIDs;
}
}
How can i call the get function?
You could call it by using object instance like:
MipRequest mipRequest = new MipRequest();
//set list...
List<String> mipIds = mipRequest.getMipIDs();
//further business logic

Java ConcurrentModificationException when using list.remove()

I've got a method called removeSup which is supposed to remove an object Supplement from a list of supplements.
this is the code for the method:
private static void removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
Iterator<Supplement> iterator = listToRemoveFrom.iterator();
while(iterator.hasNext()){
if(iterator.next().equals(supToRemove)){
iterator.remove();
}
}
}
there is a class called magazine which defines the list of supplements.
public class Magazine {
private List<Supplement> supList;
public List<Supplement> getSupList() {
return this.supList;
}
public void setSupList(List<Supplement> supList) {
this.supList = supList;
}
public Magazine(Double cost, String _name){
this.supList = new ArrayList<>();
this.weekCost = cost;
this.name = _name;
}
}
the class supplement has the following constructor
public Supplement(String _name, Double _price, String _magName ){
this.name=_name;
this.price=_price;
this.magName = _magName;
}
in the main class client there is a search that the user can do to remove a certain Supplement
private static void searchSup(){
System.out.println("Search for Supplement");
String search = scanner.nextLine();
for (Supplement sup : magazine.getSupList()) {
if (!sup.getSupName().equalsIgnoreCase(search)) {
//do something
}
else{
removeSup(sup,magazine.getSupList());
}
}
}
the main method in the client class is as follows:
private Magazine magazine;
public static void main(String[] args) {
magazine = new Magazine(3.0, "pop");
List<Supplement> startList = new ArrayList<>();
startList.add(new Supplement("Nat Geo", 3.0,"pop"));
startList.add(new Supplement("Discovery", 5.0,"pop"));
startList.add(new Supplement("Health", 6.3,"pop"));
startList.add(new Supplement("IT", 8.3,"pop"));
magazine.setSupList(startList);
searchSup();
}
When I run this program and type any of the added supplements, i get an error
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at Client.searchSup(Client.java:131)
at Client.searchSup(Client.java:140)
at Client.main(Client.java:588)
is it the for loop i am using to search giving me an error? if so how would i go about fixing this?
You generally shouldn't modify a Collection while iterating over it. It's fine to modify elements, but you really shouldn't remove something from a Collection while iterating. See here: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html. Also, the Javadoc for ConcurrentModificationException may be helpful.
You might try returning a new list with the Supplement removed:
private static List<Supplement> removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
List<Supplement> filteredSupplements = new ArrayList<Supplement>();
for(Supplement supplement : listToRemoveFrom) {
if(!suppplement.equals(supToRemove)){
filteredSupplements.add(supplement);
}
}
return filteredSupplements;
}
It seams that the "magazine" is local var in the method of main, not accessible to searchSup.Fix it like
private void searchSup(Magazine magazine)
{
//...
}
and more details if you can provide, the codes in Line 131 and 140 will be helpful.
I figured out that the search i was doing was not working with what i wanted to do so i created a method which returns an integer of the Supplement in the list.
private static int indexOfSup(List<Supplement> supSearchList, String nameOfSup) {
for (Supplement sup : supSearchList) {
if (sup.getSupName().equalsIgnoreCase(nameOfSup)) {
return supSearchList.indexOf(sup);
}
}
return -1;
}
i then use this integer to remove from the list.
a simple List.Remove(index) worked fine
Thanks for all the replies.

Categories

Resources