Iterate over heterogeneous list - java

I have a method which returns the list like
public List<Object> getSomeData(SomeBean sb) {
List<Object> data = Lists.newArrayList();
data.add(sb.getId()); // Id->long
data.add(sb.getName()); // name->String
.....
return data;
}
and Now I have to iterate over this list, which I have to check type every time as
for (int i = 0; i < data.size(); i++) {
if (data.get(i) instanceof String) {
//append
}
if (data.get(i) instanceof Long) {
//append
}
....
}
I need to append the elements of list in the loop.
Are their any better way to achieve this, may be without using instanceof operator.

You should create a class for that data and return an instance of it instead of a List.
class SomeEntity {
long id;
String name;
public SomeEntity(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
#Overrides
public String toString() {
return id + " " + name;
}
}
Just use it in your code:
public SomeEntity getSomeData(SomeBean sb) {
SomeEntity entity = new SomeEntity(sb.getId(), sb.getName());
return entity;
}
Edit: you can override the toString() method of the class and use it in your code (added above)

Here you go:
final List<Object> someData = new ArrayList<>();
someData.add("stringValue"); //String
someData.add(1L); //Long Value
final String result = someData.stream()
.map(String::valueOf)
.collect(Collectors.joining(" "));
System.out.println(result);

Related

Java Reflection traverse into nested object and list and update the fields

I have the following complex POJO class Invoice
public class Measure {
private String id;
private Float value;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public Float getValue() { return value; }
public void setValue(Float value) { this.value = value; }
}
public class LineItem {
private Integer lineNumber;
private Measure shipped;
private List<LineItem> lineItems;
public Integer getLineNumber() { return lineNumber; }
public void setLineNumber(Integer lineNumber) { this.lineNumber = lineNumber; }
public Measure getShipped() { return shipped; }
public void setShipped(Measure shipped) { this.shipped = shipped; }
public List<LineItem> getLineItems() { return lineItems; }
public void setLineItems(List<LineItem> lineItems) { this.lineItems = lineItems; }
}
public class Invoice {
private String originUid;
private String vehicleUid;
private List<LineItem> lineItems;
public String getOriginUid() { return originUid; }
public void setOriginUid(String originUid) { this.originUid = originUid; }
public String getVehicleUid() { return vehicleUid; }
public void setVehicleUid(String vehicleUid) { this.vehicleUid = vehicleUid; }
public List<LineItem> getLineItems() { return lineItems; }
public void setLineItems(List<LineItem> lineItems) { this.lineItems = lineItems; }
}
Now I want to traverse deep into every single field including nested objects in the Invoice object and update them using Reflection.
I can call updateIncomingObject() recursively. But I need to know how to get the nested objects out of the field as shown in the commented section.
public Object updateIncomingObject(Object incomingObject) {
Field[] incoming = incomingObject.getClass().getDeclaredFields();
for (Field incomingField : incoming) {
incomingField.setAccessible(true);
if (incomingField.getType().isArray()) {
// for (each occurrence in thisArray ???) {
// Object result = updateIncomingObject(occurrence);
// thisArray.set(index,result);
// }
// incomingField.set(incomingObject, thisArray);
}
else if (!incomingField.getType().getName().startsWith("java.lang")) {
// Object objInstance = incomingField.???;
// Object result = updateIncomingObject(objInstance);
// incomingField.set(incomingObject, result);
}
else {
if (incomingField.getType().equals(String.class) && incomingField.get(incomingObject) != null) {
String trimmed = incomingField.get(incomingObject).toString().trim();
incomingField.set(incomingObject, trimmed);
}
}
}
return incomingObject;
}
How do I turn field into object instance?
To access the objects of an array (fields defined with []) you can do the following:
if (incomingField.getType().isArray()) {
Object[] thisArray = (Object[]) incomingField.get(incomingObject);
for (int k = 0; k < thisArray.length; k++) {
Object occurrence = thisArray[k];
Object result = updateIncomingObject(occurrence);
thisArray[k] = result;
}
incomingField.set(incomingObject, thisArray);
}
To access the objects of a List you can do the following:
if (List.class.isAssignableFrom(incomingField.getType())) {
List<?> thisList = (List<?>) incomingField.get(incomingObject);
for (int k = 0; k < thisList.size(); k++) {
Object occurrence = thisList.get(k);
Object result = updateIncomingObject(occurrence);
thisList.set(k, occurrence);
}
}
Note: If you call updateIncomingObject when iterating on arrays/lists and the object in the array/list is an array (Object[]) your method won't do anything, because the number of declared fields for an array (Object[]) class is 0.
I hope this helps you.

How to check if an array in an arraylist contains a certain value?

I have an array list which contains arrays of type String. I create the array list and add arrays to it with the following code:
List<String[]> transaction = new ArrayList<String[]>();
String[] transactionLine = new String[7];
transactionLine[0] = "0";
transactionLine[1] = "1";
//.....
transactionLine[6] = "some value";
transactionLines.add(transactionLine);
Now I want to test if one of the arrays contain a certain value. I tried it like this, but then it checks for an array and not an element of an array:
if(transactionLines.contains("some value")) {
//Do some stuff with it
}
I know this doesn't work, but I don't now how to do it otherwise. I couldn't find any post of this already on Stackoverflow (not with the logical search terms for this problem anyway).
Note: I have chosen this structure of arrays in an arraylist, because I have a fixed number of columns (as suggested in how to create dynamic two dimensional array in java?).
Any help is greatly appreciated!
#assylias suggestion to use the object oriented way is good, but his example does not tell if the list contains a transaction where one property has a certain value. This example does:
public class Test {
public static void main(final String[] args) {
final List<TransactionLine> transaction = new ArrayList<>();
transaction.add(new TransactionLine(1, "some value"));
transaction.add(new TransactionLine(2, "another value"));
transaction.add(new TransactionLine(3, "yet another value"));
System.out.println(containsName(transaction, "some value"));
System.out.println(containsName(transaction, "non-existent value"));
}
// Iterates over all transactions until a transaction is found that has the
// same name as specified in search
private static boolean containsName(final List<TransactionLine> transaction, final String search) {
for (final TransactionLine transactionLine : transaction) {
if (transactionLine.getName().equals(search)) {
return true;
}
}
return false;
}
private static class TransactionLine {
private int id;
private String name;
public TransactionLine(final int id, final String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
}
Here is an example with two classes (Transaction and TransactionLine):
Test:
public class Test {
public static void main(final String[] args) throws Exception {
final Transaction transaction = new Transaction();
transaction.add("some name");
transaction.add("another name");
transaction.add("yet another name");
System.out.println(transaction.containsName("some name"));
System.out.println(transaction.containsName("non-existent name"));
}
}
Transaction:
import java.util.ArrayList;
import java.util.List;
public class Transaction {
private final List<TransactionLine> transactionLines = new ArrayList<>();
public void add(final String name) {
final TransactionLine tl = new TransactionLine(transactionLines.size(), name);
transactionLines.add(tl);
}
public boolean containsName(final String name) {
for (final TransactionLine transactionLine : transactionLines) {
if (transactionLine.getName().equals(name)) {
return true;
}
}
return false;
}
}
TransactionLine:
public class TransactionLine {
private int id;
private String name;
public TransactionLine() {
}
public TransactionLine(final int id, final String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
The object oriented way of solving your problem would be to create a class:
class Transaction {
private final int id;
private final String name;
//etc.
}
Then if you need to test if a given transaction is in the list you could implement equals and hashcode in that class, which would enable you to call:
if(transactionLines.contains(someTransaction)) { ... }
If you just need to find transactions with a specific characteristics, you would need to iterate over the list and check each transaction, for example:
Transaction result = null;
for (Transaction t : transacionLines) {
if(t.getName().equals("some value") {
result = t;
break;
}
}
public static boolean isListOfStringArraysContainsString(List<String[]> arrayList, String s) {
for (String[] arr : arrayList) {
for (String string : arr) {
if ((string != null) && (string.equals(s))) {
return true;
}
}
}
return false;
}
Provided code do exactly what you are asking about, but solution provided by #assylias is proper
I got your point. By using ArrayList you are trying to make an array of another array of strings. But you have made one simple mistake.This is how you tried to retrieved a String inside an array inside an ArrayList:
if(transactionLines.contains("some value")) {
//Do some stuff with it
}
This "some value" is a string present in String array "transactionLine" and not referred by the List "transactionLines" (which is referring to ArrayList object).
Instead this is what you should have done:
List<String[]> transactionLines = new ArrayList<String[]>();
String[] transactionLine = new String[7];
transactionLine[0] = "0";
transactionLine[1] = "1";
transactionLine[2] = "something";
transactionLine[3] = "3";
transactionLine[4] = "4";
transactionLines.add(transactionLine);
String[] mySL=transactionLines.get(0);
System.out.println(mySL[2]);
if (mySL[2].equals("something")) {
//some code
} else {
//some code
}
Hope this helps.

How to read recursive List in java

I can not read a recursive list of items.
I have a tree of categories, each category has children, which in turn can have children (do not know how many).
This is my class:
public class Category {
public int HasChild = 0;
public int level;
public boolean isOpened = false;
#ElementList(entry = "Category", required = false, empty = true, data = true, inline = true)
private List<Category> childrenCategory;
#Attribute(required = false)
private String id;
#ElementList(entry = "Name", inline = true, required = false)
public List<Name> name;
public List<Category> getCategoy() {
return childrenCategory;
}
public void setCategoy(List<Category> categoy) {
childrenCategory = categoy;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Name> getName() {
return name;
}
public void setName(List<Name> name) {
this.name = name;
}
#Override
public String toString() {
return "Category [childrenCategory=" + childrenCategory + ", id=" + id
+ "]";
}
}
This is my function where a foreach control Things will:
void function(Category cat) {
for (Category iterable_element : cat.getCategoy()) {
Log.i("link", iterable_element.toString());
if (cat.getCategoy() != null) {
//
// holder.btn.setEnabled(true);
// cat.HasChild = 1;
Log.i("link", "isEmpity");
}
}
Here is where you call the function, where the oject initial step:
object = category;
function(object);
my problem is that I can control in this way Things will only top level if I would like to access those second level should do:
object = category.getCategoy().get(0);
function(object);
but this is not possible because everything has to be recursive, and not hand written.
Should I once read the first iterate the oject to the next level
help me, thanks
Call the function recursively. Here is the code.
void function(Category cat) {
if (cat.getCategoy().size() > 0) {
for (Category iterable_element : cat.getCategoy()) {
log.i("Has "+cat.getCategoy().size() + " children.");
function(iterable_element); // again call it recursively
}
}
else {
log.i("No children.");
}
}

Java-Collections, cannot overwrite old value with new value

I got a question regarding Java-Collections. I iterate through a Java-Collection and if an if-clause is true, I want to change the entry of the Collection. Within the if-clause body the new Value is accepted, but if I want to print the whole collection later, it prints out again the Collection with the old value.
Here the Code:
public boolean checkConsumeStorageCapacity(Multimap<String, Values> mm1, Multimap<String, Values> mm2)
{
boolean enoughStorageCapacity = false;
Multimap<String, Values> mmApp = mm1;
Multimap<String, Values> mmHW = mm2;
Collection<Values> colA = mmApp.get("Storage");
Collection<Values> colH = mmHW.get("Memory");
for (Values vA2 : colA) {
for (Values vH2 : colH) {
if (vA2.getName().equals("Size") && vH2.getName().equals("Size")) {
float StoSize = Float.parseFloat(vA2.getValue());
float MemSize = Float.parseFloat(vH2.getValue());
float maintainableStoSize = StoSize * maintainabilityfactor;
if (MemSize >= maintainableStoSize) {
MemSize -= maintainableStoSize;
vH2.setValue(String.valueOf(MemSize));
String s = vH2.getValue();
System.out.println(s);
enoughStorageCapacity = true;
return enoughStorageCapacity;
}
break;
}
}
}
System.out.println(colH);
Values is a object containing 3 String. The getters/setters are all declared correctly. Printing out s gives the correct value, but printing out colH gives again the old value. Isnt setting the new Value enough, do I additionally have to commit anything in the Collection?
Thanks a lot in advance.
edit:
here the values class, for further understanding.
public class Values {
private String name;
private String type;
private String value;
public Values(String name, String type, String value)
{
this.name = name;
this.type = type;
this.value = value;
}
public String getName()
{
return name;
}
public String getType()
{
return type;
}
public String getValue()
{
return value;
}
public void setName(String name)
{
this.name = name;
}
public void setValue(String value)
{
this.value = value;
}
public void setType(String type)
{
this.type = type;
}
#Override
public String toString() {
return "name=" + name + ", type=" + type + ", value=" + value;
}
}
Another way of dealing with such pointer issues is to initialize a second collection before the loop. As you iterate through add the values that you want to stay the same to the collection and then in the if statement add the changed value/object. This costs a little more memory but no real performance loss
Something like this:
list<T> originallist;
list<T> tmp = new list
for(x : originalList)
{
if(condition)
{
//do things
tmp.add(changedValue)
}
else
{
tmp.add(x)
}
}

Dynamic initialization of ArrayList<anyClassObject>

Normally if we want to initialize a generic non-primitive ArrayList we do this
ArrayList<?> arrayList = new ArrayList<MyClass.class>();
But I want to do something similar to this no matter which class object I pass, i.e
private void getModel(Class responseType){
//Something similar, because this does not work..
ArrayList<?> arrayList = new ArrayList<responseType>();
}
Any Help would be greatly appreciated.
Try something like this
private <T> void setModel(Class<T> type) {
ArrayList<T> arrayList = new ArrayList<T>();
}
If you want to get the list back then
private <T> ArrayList<T> getModel(Class<T> type) {
ArrayList<T> arrayList = new ArrayList<T>();
return arrayList;
}
EDIT
A FULL EXAMPLE SHOWING HOW TO USE GENERIC TYPE FOR ARRAYLIST
Tester class with main method and the generic Method
public class Tester {
private <T> ArrayList<T> getModels(Class<T> type) {
ArrayList<T> arrayList = new ArrayList<T>();
return arrayList;
}
public static void main(String[] args) {
Data data = new Data(12, "test_12");
Magic magic = new Magic(123, "test_123");
Tester t = new Tester();
ArrayList<Data> datas = (ArrayList<Data>) t.getModels(Data.class);
datas.add(data);
for(Data data2 : datas) {
System.out.println(data2);
}
ArrayList<Magic> magics = (ArrayList<Magic>) t.getModels(Magic.class);
magics.add(magic);
for(Magic magic2 : magics) {
System.out.println(magic2);
}
}
}
Another possibility to use the same things without parameter since we don't use it inside the method
public class Tester {
private <T> ArrayList<T> getModel() {
ArrayList<T> arrayList = new ArrayList<T>();
return arrayList;
}
public static void main(String[] args) {
Data data = new Data(12, "test_12");
Magic magic = new Magic(123, "test_123");
Tester t = new Tester();
ArrayList<Data> datas = t.getModel();
datas.add(data);
for(Data data2 : datas) {
System.out.println(data2);
}
ArrayList<Magic> magics = t.getModel();
magics.add(magic);
for(Magic magic2 : magics) {
System.out.println(magic2);
}
}
}
Model class (Data)
public class Data {
private Integer id;
private String name;
public Data() {
}
public Data(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Data [" + (id != null ? "id=" + id + ", " : "") + (name != null ? "name=" + name : "") + "]";
}
}
Model class (Magic)
public class Magic {
private Integer id;
private String name;
public Magic() {
}
public Magic(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Data [" + (id != null ? "id=" + id + ", " : "") + (name != null ? "name=" + name : "") + "]";
}
}
This works:
private void getModel(){
ArrayList<?> arrayList = new ArrayList<Object>();
}
I mean, it is unclear what you are trying to do. Generics is purely compile-timem, to perform compile-time type checking. Therefore, if the type parameter is not known at compile time, it would be useless.
Try using following
public <T> List<T> getList(Class<T> requiredType) {
return new ArrayList<T>();
}
public void useList() {
List<Integer> ints = getList(Integer.class);
List<String> lists = getList(String.class);
}

Categories

Resources