Java List removing items without any action - java

I'm facing a weird behavior in my Java code using List.
The code is very simple, I have a List of Object called AccessRequest which comes from a database and I'm using this first List to create a new one but with a filter to select only a few objects.
Here is the code :
private void updateCommentIfNeeded() {
List<AccessRequest> accessRequestList = getAllRequest();
List<AccessRequest> commentsList = getCommentsListProcessedManually(accessRequestList);
}
public List<AccessRequest> getCommentsListProcessedManually(List<AccessRequest> accessRequests) {
accessRequests.removeIf(ar -> !ar.getComment().equals("To be processed manually"));
if (accessRequests.size() != 0) {
SQLServerConnection sqlServerConnection = new SQLServerConnection(sqlServerUrl);
accessRequests.removeIf(ar -> !sqlServerConnection.emailExists(ar.getEmail()));
}
return accessRequests;
}
I'm supposed to get a second List only containing the objects that has their comments to To be processed manually, which I do. But the weird part is that the first List also takes the value of the second as if I wrote accessRequestList = commentsList but there is no such thing and I'm using local variable.
Ex :
I have 3 objects in my first List, but only one containing the required comment
Both list ends with containing the only objects containing the comment
I'm kind of lost here if anyone has an idea !

Your method getCommentsListProcessedManually modifies the list you're passing. I believe you're operating under the assumption that passing the list as a parameter somehow creates a copy of the list, whereas what is actually happening is that a reference to the list is passed by value.
There are several ways to solve this, but the easiest is to simply create a copy of your input list at the start of your method:
public List<AccessRequest> getCommentsListProcessedManually(List<AccessRequest> input) {
List<AccessRequest> accessRequests = new ArrayList<>(input);
accessRequests.removeIf(ar -> !ar.getComment().equals("To be processed manually"));
if (accessRequests.size() != 0) {
SQLServerConnection sqlServerConnection = new SQLServerConnection(sqlServerUrl);
accessRequests.removeIf(ar -> !sqlServerConnection.emailExists(ar.getEmail()));
}
return accessRequests;
}
You could also use the Stream API for this (using the filter operation), but that's quite a bit trickier in this situation.

You are passing a reference of the list to the method getCommentsListProcessedManually.
So accessRequestList and the one passed as a parameter are the same, hence any operation done to the list is done to the same list.
You can create a copy of the list before passing it as a parameter:
List<AccessRequest> newList = new ArrayList<AccessRequest>(accessRequestList);

Related

Create Mono Array Object with keeping original ordering

I need to implement function that returns Mono< Array< ProcessedObject>>. As argument it takes list of objects and process them with function that returns Mono< ProcessedObject>. Function needs to keep original order, meaning first element on returned list must be created from first element from argument list. So far i have following solution but it doesn't keep required order. Is it even possible with Flux?
private fun createItems(objects: List<Someobjects>): Mono<Array<ProcessedObject>> {
return Flux.fromIterable(objects)
.flatMap {
processObject(it)
}.collectList().map { it.toTypedArray() }
}
Edit: to clarify a little processObject returns Mono< ProcessedObject>
You can try with concatMap instead of flatMap.
Here is a link for the Docu https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#concatMap-java.util.function.Function-
private fun createItems(objects: List<Someobjects>): Mono<Array<ProcessedObject> {
return Flux.fromIterable(objects)
.concatMap {
processObject(it)
}.collectList().map { it.toTypedArray() }
}
The difference between flatMap and concatMap is that the later preserves the original order.

How to copy the contents of an ArrayList in another ArrayList

public boolean isConnectedTo(Suspect aSuspect){
boolean flag = false;
Registry tempRegistry = new Registry();
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
for(Communication comms : TempComms) {
System.out.println("here");
for(String PhoneNums : phoneNumbers){
if(PhoneNums.equals(comms.GetTransmitter())) {
for(String numbers : aSuspect.getNumbersList()) {
if(numbers.equals(comms.GetReceiver()))
flag = true;
}
}
}
}
return flag;
}
So I am trying to create a program that among other things, it will search two ArrayLists(TempComs and phoneNumbers) and it will return true or false whether a string in the first is the same with a string in the second or not. I create the new ArrayList TempComms with the method tempRegistry.GetComms(). GetComms() is a method in another class, (class Registry) and has just a return communications; command, communications is an ArrayList in the class Registry.(The ArrayList phoneNumbers is an arrayList of the class the code is into.) So normally with with
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
the ArrayList TempComms must be the same with ArrayList communication that exists in the other class. But I figured out that for some reason the problem is in TempComms, because the first for is never running(For that reason I used System.out.println("here"); but it never printed). I searched and tried a lot to find the solution of this problem of my own, but I didn't manage to make some progress, so I would be grateful if someone who knows where's the problem or what I do wrong tell me about it. Thanks anyway.
You are creating a new instance of the Registry which contains a list (comms).
Registry tempRegistry = new Registry();
Then you are trying to get that comm list by calling tempRegistry.GetComms() .
Unless you are populating this communication list in the constructor Registry() (not only instantiating, you should add some entries as well),
that list will be empty when for loop is called.
(Because you are clearly NOT populating it after creating the instance tempRegistry and before calling the for loop.
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
for(Communication comms : TempComms) {
Therefore, the TempComms list is also an empty list. Which is why the inside code of the for loop is not executing.

Retreving only latest record in iteration after adding multiple values to list using java

I'm trying to add multiple records to a list and iterate. But its displaying only latest records added
Here is my code
List<ExportBean> exportBeans = new ArrayList<ExportBean>();
ExportBean exportBean = new ExportBean();
exportBean.setBooleanValue(true);
exportBean.setKeyValue("PRE_APPROVED_OFFER");
exportBean.setStringValue("111");
exportBeans.add(exportBean);
exportBean.setBooleanValue(true);
exportBean.setKeyValue("PRE_APPROVED_OFFER1");
exportBean.setStringValue("222");
exportBeans.add(exportBean);
getLopRefNo(exportBeans);
when I iterate it
def getLopRefNo = {
exportBeans->
println "in function ${exportBeans}"
}
It shows only
in function [ExportMessagingBean{stringValue='222', keyValue='PRE_APPROVED_OFFER1', exportBoolean=true}, ExportMessagingBean{stringValue='222', keyValue='PRE_APPROVED_OFFER1', exportBoolean=true}]
It doesnt show the first record added. Is it missing anything?
The problem has nothing to do with Groovy. In your code, you are not actually adding two objects, you are adding one object and modifying it.
List<ExportBean> exportBeans = new ArrayList<ExportBean>();
ExportBean exportBean = new ExportBean();
exportBean.setBooleanValue(true);
exportBean.setKeyValue("PRE_APPROVED_OFFER");
exportBean.setStringValue("111");
exportBeans.add(exportBean); // add object to list
exportBean.setBooleanValue(true);
exportBean.setKeyValue("PRE_APPROVED_OFFER1");
exportBean.setStringValue("222");
exportBeans.add(exportBean); // this time, the same reference is "added". This does not result in an addition (in fact, "add" will return false here
getLopRefNo(exportBeans);
You are calling add with an object that is already present in the list so it has no effect. What you should do is create another instance of ExportBean, like this:
List<ExportBean> exportBeans = new ArrayList<ExportBean>();
ExportBean exportBean = new ExportBean();
exportBean.setBooleanValue(true);
exportBean.setKeyValue("PRE_APPROVED_OFFER");
exportBean.setStringValue("111");
exportBeans.add(exportBean); // add object to list
exportBean = new ExportBean(); //create new instance of ExportBean
exportBean.setBooleanValue(true);
exportBean.setKeyValue("PRE_APPROVED_OFFER1");
exportBean.setStringValue("222");
exportBeans.add(exportBean); // this new instance will be correctly added
getLopRefNo(exportBeans);
You only have one ExportBean object in your code (you only said new ExportBean() once) so you have added the same object to the list twice. Your second set of calls to the set methods on the bean just updates your existing object rather than creating a new one.

Trying to compare a HashSet element with an element in a List

I have a HashSet that I created and this is what it contains. It will contain more later on, this is pasted from standard out when I did a toString on it. Just to show the contents.
foo.toString(): Abstractfoo [id=2, serial=1d21d, value=1.25, date=2012-09-02 12:00:00.0]
INFO [STDOUT] price.toString(): Abstractfoo [id=1, serial=1d24d, value=1.30, date=2012-09-19 12:00:00.0]
I have a List that I also have and I need to compare the two. One of the elements in List is:
Bar.toString(): Bar [id=1d21d, name=Dell, description=Laptop, ownerId=null]
Here is what I am trying to do...
Bar contains all of the elements I want foo to have. There will only be one unique serial. I would like my program to see if an element in the list that is in HashSet contains the id for bar. So serial == id.
Here is what I've been trying to do
Removed code and added clearer code below
I've verified the data is getting entered into the HashSet and List correctly by viewing it through the debugger.
foo is being pulled from a database through hibernate, and bar is coming from a different source. If there is an element in bar I need to add it to a list and I'm passing it back to my UI where I'll enter some additional data and then commit it to the database.
Let me know if this makes sense and if I can provide anymore information.
Thanks
EDIT: Here is the class
#RequestMapping(value = "/system", method = RequestMethod.GET)
public #ResponseBody
List<AbstractSystem> SystemList() {
// Retrieve system list from database
HashSet<AbstractSystem> systemData = new HashSet<AbstractSystem>(
systemService.getSystemData());
// Retrieve system info from cloud API
List<SystemName> systemName= null;
try {
systemName = cloudClass.getImages();
} catch (Exception e) {
LOG.warn("Unable to get status", e);
}
// Tried this but, iter2 only has two items and iter has many more.
// In production it will be the other way around, but I need to not
// Have to worry about that
Iterator<SystemName> iter = systemName.iterator();
Iterator<AbstractSystem> iter2 = systemData .iterator();
while(iter.hasNext()){
Image temp = iter.next();
while(iter2.hasNext()){
AbstractPricing temp2 = iter2.next();
System.out.println("temp2.getSerial(): " + temp2.getSerial());
System.out.println("temp.getId(): " + temp.getId());
if(temp2.getSerial().equals(temp.getId())){
System.out.println("This will be slow...");
}
}
}
return systemData;
}
If N is the number of items in systemName and M is the number of items in systemData, then you've effectively built an O(N*M) method.
If you instead represent your systemData as a HashMap of AbstractSystem by AbstractSystem.getSerial() values, then you just loop through the systemName collection and lookup by systemName.getId(). This becomes more like O(N+M).
(You might want to avoid variables like iter, iter2, temp2, etc., since those make the code harder to read.)
EDIT - here's what I mean:
// Retrieve system list from database
HashMap<Integer, AbstractSystem> systemDataMap = new HashMap<AbstractSystem>(
systemService.getSystemDataMap());
// Retrieve system info from cloud API
List<SystemName> systemNames = cloudClass.getImages();
for (SystemName systemName : systemNames) {
if (systemDataMap.containsKey(systemName.getId()) {
System.out.println("This will be slow...");
}
}
I used Integer because I can't tell from your code what the type of AbstractSystem.getSerial() or SystemName.getId() are. This assumes that you store the system data as a Map elsewhere. If not, you could construct the map yourself here.

JSF not retaining the original List and mixing modified and original List OR How to do a deep copy of an ArrayList in JSF 2.0 ModelBean

I am using JSF2.0 in my application.
The business requirement in my project is such that when page loads a list is displayed. The list is coming from DAO layer or web service layer. Lets call this original List.
Now we have 2 lists, copies of each other in which is just the original list and the other is bounded to the JSF
Now the list is editable list so I am using a to display the list and each cell in the is a .
Now on click of SAVE button the modified list by the user (since the list is editable) is compared with the original list.
Only if the 2 lists are different then the modified list is sent back to webservice.
The problem and issue that I am facing is that in the first line of save() method itself both the original and modified list is exactly same and point only to the modified list.
So I am unable to compare the 2 lists.
My implementation is as below-
PhaseListener is calling below method on page load
public String populateDataTable() {
this.orderList = new ArrayList<ItemOrder>();
this.originalOrderList = new ArrayList<ItemOrder>();
MockWebService mockService = new MockWebService();
this.setOrderList(mockService.mockWSMethod());
this.originalOrderList = this.getOrderList();//i know this is where i am doing something wrong. i need to deep copy a list. but for this i cannot make an additional web service call and call that web service again and store the list in originalOrderList
return "view";
}
On click of save button
public String saveAction() {
boolean isSame = true; // true if same and false if different
for (int i = 0; i < this.originalOrderList.size(); i++) {
if (!this.originalOrderList.get(i).equals(this.orderList.get(i))) {
isSame = false;
}
}
//however both originalOrderList and orderList have the same modified List.
if (isSame == true) {
System.out.println("Same lists");
} else {
System.out.println("Different lists");
}
return "default";
}
Please do help me.
Thanks in advance,
Kiran
As you mentioned the problem you are facing is originalOrderList is a shallow copy of orderList (assuming getOrderList() is returning an orderList reference). In your case both orderList and originalOrderList are references pointing to the same ArrayList object and if a change is made to the value of your orderList, then the originalOrderList reflects that change because it shares the same reference.
The solution is to do a deep copy of your originalOrderList :
this.originalOrderList = this.getOrderList().clone();
if your ItemOrder is an immutable object otherwise :
public static List<ItemOrder> cloneList(List<ItemOrder> list) {
List<ItemOrder> clone = new ArrayList<ItemOrder>(list.size());
for(ItemOrderitem: list) clone.add(item.clone());
return clone;
}
and you will have to get your ItemOrder object to implement the Cloneable interface, and implement the clone() method.

Categories

Resources