I'm new to java and what I'm currently trying is.
For example I have 2 classes 1 for Employees which can have a name number and email and one for Vehicles which have number type and status.
I retrieve data from an API for both classes and fill and ArrayList<Employee> and ArrayList<Vehicle> with all the data.
Both of these classes need to go through the same function which will create an excel file based on the data.
The problem I'm facing currently is that I want to use both of these arraylist in my function but based on which one I get to do other things inside the function and for this I need to know which arraylist was forwarded to the function. What I'm trying to do is following:
I have a function
Public static void createExcel(Object[] obj){ //do something }
I give the function the type Object so that I can get both of the arraylists. So I parsed the Arraylists as followed:
ArrayLists<Employee> employees = new ArrayList<>();
employees.add(employee);
Object[] objArray = employees.toArray();
ExcelWriter.createExcel(objArray);
The same for Vehicle.
Now my question is how can I in the createExcel funtion retrieve which arraylist was passed and how can I get my original arraylist from this object array? or is this not possible and do I have to do it another way?
EDIT:
To make it a bit more clear I would like my excel function to be something like this:
if(obj == type of ArrayLists<Employee>()){ //retrieve my original employees arraylist here }
And the same for Vehicle
You can check the actual type of an object using instanceof:
public static void createExcel(Object[] obj){
// Assume array is not empty
Object o = obj[0];
if ( o instanceof Employee ) {
// It's an Employee
}
else if ( o instanceof Vehicule ) {
// It's a Vehicule
}
else {
// Should probably throw an Exception here
}
}
But if you wish to do different things dependening on the type of the parameter, why would you write a single function?
Override createExcel method
public static void createExcel(List<Employee> employees){
...
ExcelWriter.createExcel(employees.toArray());
...
}
public static void createExcel(List<Vehicle> vehicles){
...
ExcelWriter.createExcel(vehicles.toArray());
...
}
Related
Without generics it is possible to create an ArrayList with elements of different types. I want to iterate through it and put out the elements. I can not use a for-each-loop, because it wants a specific type. I tried Iterator but wasn't successful.
So I have two questions:
Is it possible to iterate through an array list and put out (e. g. with System.out.println) all elements no matter of which type they are?
Is it possible to iterate through an array list and put out only the elements which are of a specific type (e. g. only the Strings)?
Sure!
The toString method is defined on the Object class. The Object class is the base class of every user-defined class. You could easily write:
for (Object item: itemList) {
// prints all items
System.out.println(item);
if (item instanceof YourDesiredClass) {
YourDesiredClass specificItem = (YourDesiredClass) item;
//doSomethingElse(specificItem)
}
}
Is it possible to iterate through an array list and put out (e. g.
with System.out.println) all elements no matter of which file type
they are?
Yes, You can use the Object class
List<Object> myList = new ArrayList<>();
myList.add("Hello World"); // string
myList.add(Math.PI); // a double
myList.add(188); // an int
myList.add(9099099999999L); // a Long
// for java8
myList.forEach(System.out::println);
//before java8
for (Object object : myList) {
System.out.println(object);
}
Is it possible to iterate through an array list and put out only the
elements which are of a specific file type (e. g. only the strings)?
Yes, you can use the iterator and get the Object checking it against the class you need....
Iterator<Object> it = myList.iterator();
while (it.hasNext()) {
Object x = it.next();
if (x instanceof String) {
System.out.println("this is a String: " + x);
}
}
As far as I know, yes.
You can make ArrayList which contains Objects (see Java class Object), because each class you define in Java at least extends class Object which is a top class.
Now let me answer your questions:
yes, it is. Each object in the list knows which class it is instance of and has method toString(). When you swipe through ArrayList and call toString() for every object, the most specific method toString() will be called. For example, if it's instance of Integer (let's say it's called number) and you casted it to Object, call number.toString();, although compiler now looks at that number as the Object, it will call toString() method from Integer class. That's called dynamic polymorphism
yes, you can check which class is the Object instance of. Each of these objects has that info; casting it to Object class is just like saying to compiler "here is some object, I want you to look at it as an instance of class Object" - just like putting glasses to a compiler.
And object knows which class it is, so you can just ask, for example:
if(myObject instanceof String){
//do something;
}
Hope it helped, I tried to explain it the best way I could so you understand what's going on "under the hood" :)
Just object
new ArrayList<Object>().iterator().forEachRemaining(element -> {
System.out.println(element);
});
A specific type
new ArrayList<Object>().stream().filter(element -> element instanceof String).iterator()
.forEachRemaining(System.out::println);
Edit: this answer requires Java 8
Is it possible to iterate through an array list and put out (e. g. with System.out.println) all elements no matter of which file type they are?
Sure, you can iterate a list (or arraylist) of Objectclass and do what you need.
Is it possible to iterate through an array list and put out only the elements which are of a specific file type (e. g. only the strings)?
Yes, you can use instanceof and do specific actions for specific classes.
Usage example:
List<Object> genericList = new ArrayList<>();
genericList.add("test");
genericList.add(2);
genericList.add('c');
for (Object object: genericList) {
// "Put" out object (question 1)
System.out.println(object);
// Check object type (question 2)
if (object instanceof AnyClass) {
//doSomething()
}else if (object instanceof AnotherClass){
//doSomethingElse()
}
}
You can always use a Type all the Objects have in common. The last one will always be Object, since every Class extends Object.
But since we don't like to cast it's mostly the better approach to build a basic class for that:
public abstract class FileType
{
public abstract String getTypeName();
public abstract String getTypeDescription();
}
public class JSON extends FileType
{
#Override
public String getTypeName()
{
return "JSON";
}
#Override
public String getTypeDescription()
{
return "JavaScript Object Notation";
}
}
public class TXT extends FileType
{
#Override
public String getTypeName()
{
return "TXT";
}
#Override
public String getTypeDescription()
{
return "Textfile";
}
}
Now you can make a List of FileType's and use the Methods of it:
List<FileType> fileTypes = new ArrayList<>();
list.add(new JSON()); // JSON fits good in here
list.add(new TXT()); // TXT also
for (FileType fileType : list)
{
System.out.println(fileType.getTypeName()); // have the FileType-Methods savely available
}
I'm currently working on Storm.
In Storm, for those of you might not know, it takes in whatever value types and emits as object type.
My problem is, I need to work with lists; should be able to access each item by index. But it would end up sent as an object anyway.
I have tried converting ex-list object to String type, parse each item by ", " and stored it in another list as a countermeature. It works fine but it looks like a messy way.
Another way I have tried was simply type cast the object to list. It has no compile errors, but the new list only has size of 1, and the only item in that list is the ex-list object that I need to convert to.
How can I convert ex-list object to list in sophisticated way?
I'm sorry if this is a juvenile question, and thanks in advance.
To inform you specific, the following snippet is the situation that converting has to happen.
public class TridentSpoutTest implements IBatchSpout{
emitBatch(...) {
List<String> list = new ArrayList<String>();
list.add("This");
list.add("is");
list.add("test");
collector.emit(new Values(list));
}
}
public class TridentFuncTest extends BaseFunction {
public void execute(TridentTuple tuple, TridentCollector collector){
OrdinaryClass.put(tuple.getValueByField("data"));
//getValueByField returns value in Object type
}
}
public class OrdinaryClass {
public void put(Object o) {
//How to convert o back to list?
}
}
As long as your list-type implements Serializable there should be no problem. Let's assume a Spout emits a lists and a bolt receives it:
// Spout.nextTuple()
public void nextTuple() {
List<String> l = new ArrayList<String();
l.add("a");
l.add("b");
l.add("c");
// l gets stored at index zero
collector.emit(new Values(l));
}
// Bolt.execute()
public void execute(Tuple input) {
// receive from index zero and cast
// (cast to ArrayList<String> would also work)
List<String> l = (List<Array>)input.getValue(0));
// you can access "a", "b", and "c" via l.get(0), l.get(1), l.get(2)
}
In your case, you need to use the proper types and add a cast (similar to my example):
public class OrdinaryClass {
// if it's a list, you type List (or ArrayList, LinkedList if you know the concrete list type)
public void put(List o) {
}
}
// for calling "put" add cast to proper type
OrdinaryClass.put((List)tuple.getValueByField("data"));
So I have code that looks like this:
public void success(List<Object> profiles, Response response) {
List<MyCustomObject> list= new ArrayList<MyCustomObject>();
for (Object profile : profiles) {
list.add((MyCustomObject) profile); // this line crashes
}
}
So I get a ClassCastException at line noted above. Can I do this?
Here is what I am TRYING to do, my real code is a bit more complicated:
I have a List that contains two types of Objects. So, I am using the Object to hold both. Then, once I receive this list from the server, I want to break the list into two lists of my Custom Object (For example, List<MyCustomObject> instead of List<Object>. So I am doing the cast above in my for loop so I can store the incoming generic object into its specific type of object list.
Is there another way to do this? Am I on the right track?
You should add a safety check before the cast to prevent code from crashing.
List<MyCustomObject> list= new ArrayList<MyCustomObject>();
int index = 0;
for (Object profile : profiles) {
// Safety check before casting the object
if (profile instanceof MyCustomObject) {
list.add((MyCustomObject) profile); // wont crash now
} else {
// other type of object. Handle it separately
}
}
This is regarding the usage of ArrayList returned by another class instance variable.
Class A {
//assigned list of string to it.
private List < String > newAl;
//returns the list
public List < String > getList() {
return newA1;
}
}
Class Test {
public void go() {
List < String > list = a.getList();
list.add("");
}
}
In the Test class when i retreive list and manipulate the list.Because of the reference ,class A list also got manipulated.If A is part of third party code.How do I correct my code in Test class so that original object wouldnt be affected?
The ArrayList constructor takes a Collection so you can use that:
List<String> list = new ArrayList(a.getList());
I think it's better to do it like this, but depending on what you're doing, you may want to construct the new List in the getter. That also helps type hiding.
I'm trying to create a class that can instantiate arrays at runtime by giving each array a "name" created by the createtempobjectname() method. I'm having trouble making this program run. I would also like to see how I could access specific objects that were created during runtime and accessing those arrays by either changing value or accessing them. This is my mess so far, which compiles but gets a runtime exception.
import java.lang.reflect.Array;
public class arrays
{
private static String temp;
public static int name = 0;
public static Object o;
public static Class c;
public static void main(String... args)
{
assignobjectname();
//getclassname();//this is supposed to get the name of the object and somehow
//allow the arrays to become updated using more code?
}
public static void getclassname()
{
String s = c.getName();
System.out.println(s);
}
public static void assignobjectname()//this creates the object by the name returned
{ //createtempobjectname()
try
{
String object = createtempobjectname();
c = Class.forName(object);
o = Array.newInstance(c, 20);
}
catch (ClassNotFoundException exception)
{
exception.printStackTrace();
}
}
public static String createtempobjectname()
{
name++;
temp = Integer.toString(name);
return temp;
}
}
Create a Map then you can add key/value pairs when the key is your name and the value is your array.
Following up from #Ash's answer, here is some illustrative code. Notice that there is no reflection involved.
Map<String, Object> myMap = new HashMap<String, Object>();
...
Object myObject = ...
myMap.put("albert", myObject); // record something with name "albert"
...
Object someObject = myMap.get("albert"); // get the object named "albert"
// get("albert") would return null if there nothing with name "albert"
EDIT I've edited the example to use the type Object, since that is more closely aligned with what you are trying to do (I think). But you could use any type instead of Object ... just replace the type throughout the example. And you can do the same with an ArrayList; for example:
List<Date> dates = new ArrayList<Date>();
dates.add(new Date());
Date firstDate = dates.get(0);
Notice that no typecasts are required.
I expect you're getting a ClassNotFoundException from this line:
c = Class.forName(object);
The value of object the first time it's called is "1", which is not a valid class name.
Class.forName requires a class name as input, such as "java.lang.Integer". Trying to "name" your array in this way doesn't make sense to me. You need to pick an appropriate Java class name.
If you want to "name" an array instance (after you've created it), you could always store the instance as the value in a Map, using the name as the key.