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"));
Related
This seems very simple but I can't quite figure out why this isn't working.
I want to reverse the elements in my LinkedList which I have a working method for, but I can't return the value as my prof wants it to be a void method. How would I go about this?
import java.util.LinkedList;
public class ListUtil {
public static void reverse(LinkedList<String> strings) {
LinkedList<String> reverseLinkedList = new LinkedList<>();
for(int i = strings.size() - 1; i >= 0; i--) {
reverseLinkedList.add(strings.get(i));
}
strings = reverseLinkedList;
System.out.println(strings);
}
}
import java.util.LinkedList;
public class ReverseTester {
public static void main(String[] args) {
LinkedList<String> employeeNames = new LinkedList<>();
employeeNames.addLast("Dick");
employeeNames.addLast("Harry");
employeeNames.addLast("Romeo");
employeeNames.addLast("Tom");
ListUtil.reverse(employeeNames);
System.out.println(employeeNames);
System.out.println("Expected: [Tom, Romeo, Harry, Dick]");
}
}
In my ListUtil class, it does reverse the list, but doesnt return a value (as it is void) but I don't know how to go about setting employeeName in the ReverseTester class.
I know this is probably super simple but I have not been able to figure this out for the life of me, any help is greatly appreciated.
Empty and re-fill the existing list rather than replacing it.
public static void reverse(LinkedList<String> strings) {
List<String> temp = new ArrayList<>(strings); // Copy the contents of the original list. Pass the original list to constructor of our duplicate list.
strings.clear(); // Empty the original list.
for (String e : temp)
strings.addFirst(e); // Refill the original list using elements from our duplicate list.
}
Or simply
public static void reverse(LinkedList<String> strings) {
Collections.reverse(strings);
}
Non-primitive Java object are stored by reference so you don't need to return anything from ListUtil::reverse. Any changes made to the object in the function will be reflected in ReverseTester.java. This happens because, again, non-primitive Java objects are stored by reference. Basically your code does exactly what you want it to do. You make a LinkedList, populate it with items, and then reverse those items.
You will have a problem with System.out.println(employeeNames); though. Because that will just print the object's formal name and not it's contents. If you want to print the contents of a list in Java you can do:
for (String name : employeeNames) {
System.out.println(t);
}
This is my first answer so please ask any questions if I wasn't clear enough!
I created a generic java function to read a list of files. The function is created in HdfsClient class, then I should call it in another class, I loop the list of the files and I open them.
Function code:
public listeFileHdfs(String hdfsPath)
{
if(hdfs!=null)
{
try
{
Path HdfsPath = new Path(hdfsPath);
this.hdfs.listFiles(HdfsPath, false); **==> listFiles() is a defined function in HDFS client**
}
catch(IOException e)
{
logger.error("files not exist:", hdfsPath, e.getMessage());
}
}
}
My question, does this function should take a return type ? If yes which type should it List<String>, List<JSON> or just void ?
Can user decide the context?
interface Base<T> {
List<T> get();
}
class Derived implements Base<Integer> {
public List<Integer> get() {
return null;
}
}
If the user can infer the context of the returned type (based on multiple implementations of your class), and the method is always expected to return a list, then
List<T> listeFileHdfs(String hdfsPath)
In this case,
the user can expect an implementation that will return file names as String as List<String>
the user can expect an implementation that will not return anything as List<Void>
the user can expect an implementation that will return Custom object as List<CustomObject>
Alternatively, the type based simply T which gives bigger flexibility for implementations but causes a greater abstraction that should be resolved correctly by the end user.
T listeFileHdfs(String hdfsPath)
This gives flexibility to return any type
though increases flexibility will add complexity for code maintainers
So, you can choose this based on expected use case.
Updated based on comment
List<?> - returning this will be make it difficult for the consumers to infer the type.
if ? is to be used, it will be good to bound to a type, say List<? extends SomeType>
eg: This allows bounded(compile time controlled) inserts to the list
List<? super Number> list = new ArrayList<>();
list.add(1);
This does not allow inserts to the list (nearly nothing)
List<?> list = new ArrayList<>();
list.add(new Object()); // this will be compile time error
list.add(null); // this is only allowed
This does not allow inserts too, but has type safety for usage
List<? extends Number> anything = somefunction_returning_a_subclass_of_number();
It depends on what you expect the function does. Here is how I would decide the function signature.
If you want to extract the list of files from JSON format and convert it into simpler one and, possibly, make it available for the invoker, I would change the name of the function and return List<String>, like this:
public List<String> getListFileHdfs(String hdfsPath)
On the other hand, if the function is supposed do some internal elaboration with that list of files, I would change the name of the function and return void:
public void elaborateListFileHdfs(String hdfsPath)
Moreover, if you just want to print out the list of the files, I would leave the name as it is and return void.
[EDIT]
To answer your question in the comment, I suggest that you leave String as input, which is the path of the Hadoop directory. Your function should look like as follow:
public List<String> getListFileHdfs(String hdfsPath)
{
List<String> paths = new ArrayList<>();
if(hdfs!=null)
{
try
{
Path HdfsPath = new Path(hdfsPath);
RemoteIterator fileIter = hdfs.listFiles(new Path(path), recursive);
while (fileIter.hasNext()) {
String filePath = ((LocatedFileStatus) fileIter.next()).getPath().toString();
paths.add(filePath);
}
}
catch(IOException e)
{
logger.error("files not exist:", hdfsPath, e.getMessage());
}
}
return paths;
}
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());
...
}
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
}
Could you help me understand the difference between unbounded wildcard type List and raw type List?
List<?> b; // unbounded wildcard type
List a; // raw type
Along with this can anybody help me understand what is a bounded type parameter list?
List<E extends Number> c;
Here's a summary of the three:
List: A list with no type parameter. It is a list whose elements are of any type -- the elements may be of different types.
List<?>: A list with an unbounded type parameter. Its elements are of a specific, but unknown, type; the elements must all be the same type.
List<T extends E>: A list with a type parameter called T. The supplied type for T must be of a type that extends E, or it is not a valid type for the parameter.
You should really look at Effective Java, Item 23: Don't use raw types in new code.
To use the example from that book, consider the following example... what if you have a collection where you do not care what types of elements are in it. For example, you want to see how many elements are in common between two sets. You might come up with the following:
public static int numElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o : s1) {
if (s2.contains(o)) {
++result;
}
}
return result;
}
This example, while it works, is not a good idea to use because of the use of raw types. Raw types just aren't type safe at all... you could end up modifying the set in a way that is not type safe and corrupt your program. Instead, err on the side of caution and use the type safe alternative:
public static int numElementsInCommon(Set<?> s1, Set<?> s2) {
int result = 0;
for (Object o : s1) {
if (s2.contains(o)) {
++result;
}
}
return result;
}
The difference is that you can only add null to a Set<?>, and you CANNOT assume anything about the element you take out of a Set<?>. If you use a raw Set, you can add anything you want to it. The numElementsInCommon method is a good example where you don't even need to add anything and you don't need to assume anything about what is in the set. That's why it's a good candidate for using the ? wildcard.
Hope this helps. Read that whole Item in Effective Java and it will really become clear.
To answer the second part of your question... remember that I said when you use the ? wildcard, you cannot assume anything about the element you take out of the set? What if you do need to make an assumption about the interface of the object you removed from the set. For example, suppose you want to keep track of a set of Cool things.
public interface Cool {
// Reports why the object is cool
void cool();
}
Then you might have some code like this:
public static void reportCoolness(Set s) {
for (Object item : s) {
Cool coolItem = (Cool) item;
coolItem.cool();
}
}
This is not type safe... you need to make sure you passed in a set with only Cool objects. To fix it, you might say:
public static void reportCoolness(Set<Cool> s) {
for (Cool coolItem : s) {
coolItem.cool();
}
}
This is great! Does exactly what you want and is type safe. But what if later you have this:
public interface ReallyCool extends Cool {
// Reports why the object is beyond cool
void reallyCool();
}
Since all ReallyCool objects are Cool, you ought to be able to do the following:
Set<ReallyCool> s = new HashSet<ReallyCool>();
// populate s
reportCoolness(s);
But you can't do that because generics have the following property: Suppose B is a subclass of A, then Set<B> is NOT a subclass of Set<A>. The technical talk for this is "Generic types are invariant." (As opposed to covariant).
To get the last example to work you would need to create a Set<Cool> by casting (safely) every element in the Set<ReallyCool>. To avoid letting clients of your api go through this nasty, unnecessary code, you can just make the reportCoolness method more flexible like this:
public static void reportCoolness(Set<? extends Cool> s) {
for (Cool coolItem : s) {
coolItem.cool();
}
}
Now your method takes any Set that contains elements that are Cool or any subclass of Cool. All of these types adhere to the Cool api... so we can safely call the cool() method on any element
Make sense? Hope this helps.
On your first question, the difference between List and List<?>:
One significant difference between the two is that when you have an wildcard as the type, the type of the Collection is unknown, so the add method will throw a compile time error.
You can still get values out of the List<?>, but you need an explicit cast.
Both cases let us put into this variable any type of list:
List nothing1 = new ArrayList<String>();
List nothing2 = new ArrayList();
List nothing3 = new ArrayList<>();
List nothing4 = new ArrayList<Integer>();
List<?> wildcard1 = new ArrayList<String>();
List<?> wildcard2 = new ArrayList();
List<?> wildcard3 = new ArrayList<>();
List<?> wildcard4 = new ArrayList<Integer>();
But what elements can we put into this objects?
We can put only String into List<String>:
List<String> strings = new ArrayList<>();
strings.add("A new string");
We can put any object into List:
List nothing = new ArrayList<>();
nothing.add("A new string");
nothing.add(1);
nothing.add(new Object());
And we can't add anything (but for null) into List<?>! Because we use generic. And Java knows that it is typed List but doesn't know what type it is exact. And doesn't let us make a mistake.
Conclusion: List<?>, which is generic List, gives us type safety.
P.S. Never use raw types in your code.