How to call a method from a generic class as parameter - java

I've tried to make my code use generics, but I can't seem to get it to work using generics. Any help would be appreciated.
I have 3 classes: Classroom, Course, Teacher
I have the following working code 3 times: (With the small change of the class)
private ObservableList<Classroom> parseClassrooms() {
// create new Observable List
ObservableList<Classroom> classrooms = FXCollections.observableArrayList();
// get lines from file;
ArrayList<String> arrayList = fhClassroom.read();
for (String line : arrayList) {
classrooms.add(Classroom.fromString(line));
}
return classrooms;
}
Methods in my Classes:
#Override
public String toString() {
return name;
}
public static Classroom fromString(String line) {
return new Classroom(line);
}
Is it possible to make this method generic? and pass the class as parameter?
I would like something like the following:
private ObservableList<T> parseClassrooms(T, FileHelper fh) {
// create new Observable List
ObservableList<T> items = FXCollections.observableArrayList();
// get lines from file;
ArrayList<String> arrayList = fh.read();
for (String line : arrayList) {
items.add(T.fromString(line));
}
return items;
}

My best attempt:
import java.util.ArrayList;
import java.util.function.Function;
public class Helper {
public static <T> ObservableList<T> parseItems(Function<String, T> lineToItemFunction, FileHelper fh) {
// create new Observable List
ObservableList<T> items = FXCollections.observableArrayList();
// get lines from file;
ArrayList<String> arrayList = fh.read();
for (String line : arrayList) {
items.add(lineToItemFunction.apply(line));
}
return items;
}
}
And you call it this way:
ObservableList<ClassRoom> classRooms = Helper.parseItems(ClassRoom::fromLine, fileHelper);

Related

Java: For loop on Objects of Strings

I'm new in Java and I have to solve this exercise. I have this code:
public class StringList {
private String list = "";
public StringList(String... str) {
for (String s : str) list += s+"\t";
}
}
and I have to change the class so that its objects allow the iteration by using this instruction:
for (String s : new StringList("a", "b", "c")) System.out.println(s);
My idea was to create a List and iterate on it. So I changed the code in this way:
public class StringList {
private List<String> list = new ArrayList<String>();
public StringList(String... str) {
for (String s: str) list.add(s);
}
}
but when I try the iteration with the above instruction I get this error (Can only iterate over an array or an instance of java.lang.Iterable) and I spent hours trying to fix it but I keep failing. Any help?
To do it the clean way, give a look at the java.lang.Iterable interface : https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html
If your StringList class implements it, then the instruction will work. I'll let you complete the exercise yourself though, but you can start with
public class StringList implements Iterable<String> {
// the attribute you need to store the strings object
// your constructor
#Override
public Iterator<String> iterator() {
// This is what you need to fill
}
}
PS : Using a list of string as an attribute is not a bad idea at all and will save you a lot of efforts and time, search what you can do with it
You have to implement Iterable<String> to your StringList like this:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.function.Consumer;
public class StringList implements Iterable<String> {
private List<String> list = new ArrayList<String>();
public StringList(String... str) {
for (String s: str) { list.add(s); }
}
#Override
public Iterator<String> iterator() {
return list.iterator();
}
#Override
public void forEach(Consumer<? super String> action) {
list.forEach(action);
}
#Override
public Spliterator<String> spliterator() {
return list.spliterator();
}
}

Instantiating DynamoDBQueryExpression with generic classtypes

Edit: I was trying to simplify my problem at hand a little, but turns out, it created more confusion instead. Here's the real deal:
I am working with AWS's Java SDK for DynamoDB. Using the DynamoDBMapper class, I am trying to query DynamoDB to retrieve items from a particular table. I have several objects that map to my DynamoDB tables, and I was hoping to have a generic method that could accept the mapped objects, query the table, and return the item result.
Psudo-code:
#DynamoDBTable(tableName="testTable")
public class DBObject {
private String hashKey;
private String attribute1;
#DynamoDBHashKey(attributeName="hashKey")
public String getHashKey() { return this.hashKey; }
public void setHashKey(String hashKey)
#DynamoDBAttribute(attributeName="attribute1")
public String getAttribute1() { return this.attribute1; }
public void setAttribute1(String attribute1) { this.attribute1 = attribute1; }
}
public class DatabaseRetrieval {
public DatabaseRetrieval()
{
DBObject dbObject = new DBObject();
dbObject.setHashKey = "12345";
DBRetrievalAgent agent = new DBRetrievalAgent;
dbObject = agent.retrieveDBObject(dbObject.getClass(), dbObject);
}
}
public class DBRetrievalAgent {
public Object retrieveDBObject(Class<?> classType, Object dbObject)
{
DynamoDBQueryExpression<classType> temp = new DynamoDBQueryExpression<classType>().withHashKeyValues(dbObject);
return this.dynamoDBMapper.query(classType, temp);
}
}
Use a type witness within your method:
public <T> String getResult(Class<T> type) {
List<T> newList = new ArrayList<>();
//other code
}
Try this
ArrayList<T> newList = new ArrayList<>();
You can specify the type as T for your getResult() to make it generic (i.e., accepts any class) as shown below:
public <T> String getResult(T t) {
String result = "";
List<T> newList = new ArrayList<>();
// perform actions
return result;
}

Is it possible to check, if a function was called?

I have an ArrayList of objects, which I need to sort using two attributes (using Comparators). I need to save the sorted output to a text file with a different name, depending on the attribute used to sort. For example, if the list is sorted by attribute1 then file will be attribute1.txt, if attribute2 the file will be attribute2.txt.
How I want it to work (pseudocode):
if(sortedByAtr1){
FileWriter fwstream = new FileWriter(sortedByAtribute1.getName()+".txt");
}
else(sortedByAtr2){
FileWriter fwstream = new FileWriter(sortedByAtribute2.getName()+".txt");
}
Is this possible?
I appreciate any advice.
Thanks.
Servo
Here's an object-oriented approach to solving this requirement.
Use a wrapper for the List and its sorting attribute:
public class ListSorter<V> {
private final List<V> values;
private String sortingAttribute;
public ListSorter(List<V> values) {
this.values = values;
}
public void sort(AttributeComparator<V> comparator) {
Collections.sort(values, comparator);
sortingAttribute = comparator.getSortingAttribute();
}
public String getSortingAttribute() {
return sortingAttribute;
}
}
Extend the Comparator interface so you can get your attribute name:
public interface AttributeComparator<T> extends Comparator<T> {
public String getSortingAttribute();
}
Create custom AttributeComparators like this:
public class FooBarComparator implements AttributeComparator<Foo> {
public int compare(Foo foo1, Foo foo2) {
// skipped nullchecks for brevity
return foo1.getBar().compare(foo2.getBar());
}
public String getSortingAttribute() {
return "bar";
}
}
Use:
List<Foo> yourList = new ArrayList<Foo>();
ListSorter<Foo> example = new ListSorter<Foo>(yourList);
AttributeComparator comparator1 = new FooBarComparator();
example.sort(comparator1);
FileWriter fwstream = new FileWriter(example.getSortingAttribute() +".txt");

Java Android Arraylist string to ArrayList custom class

How can I convert values here:
List<String> values = new ArrayList<String>
to :
ArrayList<Custom>
EDIT:
public class Custom {
public Custom Parse(String input) {
// What should I do here?
}
}
You could use:
List<Custom> customList = new ArrayList<Custom>();
for (String value: values) {
customList.add(new Custom(value));
}
Although it would be better just to add a constructor with a String argument:
class Custom {
private final String input;
public Custom(String input) {
this.input = input;
}
// not needed but implemented for completeness
public static Custom parse(String input) {
return new Custom(input);
}
}
Assuming your list of Custom objects has the same size with values list.
With one enhanced for-loop, set the appropriate fields of your objects like this:
int i=0;
for(String str:values)
customList.get(i++).setSomeProperty(str);
you can find a solution using Google Collections libraries on this thread Converting a List<String> to a List<Integer> (or any class that extends Number)

Need to loop over an array/list/whatever and *return to caller* each element -but the loop only runs once, of course

I'm obviously missing something here, as this sound basic enough but yet...
I have a collection of objects . I need to use each one of them as parameter in constructor for a new object and return each new object to the caller method, one by one.
But -if I loop over the collection obviously the loop only runs once, and only returns the 1st object.
Edit : Returning the whole collection or some new collection will not work because :
The caller method [not mine to change] runs inside a start() method of a Runnable ThingProvider, which returns a single Thing whenever a request is submitted to it. So, returning List is not possible.
Thanks :)
public List<T> loop(Collection<? extends U> coll) {
List<T> a = new ArrayList<T>();
for (U u : coll){
a.add(new T(u));
}
return a;
}
Return a custom Iterator. Assumming your new objects are of class MyObject and the constructor accepts an Object:
public Iterator<MyObject> myObjectsIterator(final Iterator<? extends Object> it) {
return new Iterator<MyObject>() {
public boolean hasNext() {
return it.hasNext();
}
public MyObject next() {
return new MyObject(it.next());
}
public void remove() {
it.remove();
}
};
}
And you would call it like this:
...
Iterator<MyObject> myIt = myObjectsIterator(myListOfObjects.iterator());
// Now you can pass myIt around as a normal object. It will remember
// which one is the next Object with which to construct a MyObject
// and will generate it on the fly
...
while (myIt.hasNext()) { // is there any MyObject remaining?
MyObject myObj = myIt.next(); // gets the next MyObject
// do something with myObj
}
...
This is a poorly worded question and I think as others have noted, just returning a new list of the objects is fine. But if you really want to process them one at a time while you're looping through it, you can use the command pattern.
public interface Command {
void execute(NewType object);
}
Now in your caller method, you can do the following:
public void doSomething() {
processList(myList, new Command() {
void execute(NewType object) {
// Do whatever you want with this object
}
});
}
And, in the method that will actually go through the list:
public void processList(Iterable<OldType> values, Command command) {
for(OldType v : values) {
NewType newType = new NewType(v);
command.execute(newType);
}
}
In java you can return only once. So if you want to get some informations from your methods either you wrap them into a "Big" Object (here a List) or you give to the method the means to put informations in your parameters.
You could have something like this :
public static void main(String... args){
List<Parameter> parameters = methodToGetParameters();
List<Result> results = generateObjectsFromList(parameters);
for(Result result : results){
handleAResult(result);
}
}
public List<Result> generateObjectsFromList(List<Parameter> parameters){
List<Result> results = new ArrayList<Result>();
for(Parameter parameter : parameters){
results.add(new Result(parameter));
}
return results;
}
Or like this :
public static void main(String... args){
List<Parameter> parameters = methodToGetParameters();
List<Result> results = new ArrayList<Result>();
generateObjectsFromList(parameters, results);
for(Result result : results){
handleAResult(result);
}
}
public void generateObjectsFromList(List<Parameter> parameters, List<Result> results){
for(Parameter parameter : parameters){
results.add(new Result(parameter));
}
}
A third way to do this would be to use fields, but it's not really good to have a lot of fields if they're not really used (or only by one method).
On the same topic :
Java Object Oriented Design Question: Returning multiple objects in java(Updated)
Using a java method to return multiple values?
Return a collection from the method and in the collection implement a custom iterator to transform the input collection to the new collection. The following code shows how to do it using the Google Guava library:
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
public class Test {
static class Person {
public final String name;
public Person(String name) {
this.name = name;
}
}
public static Collection<Person> peopleFromNames(Collection<String> names) {
return Collections2.transform(names, new Function<String, Person>() {
public Person apply(String name) {
return new Person(name);
}});
}
public static void main(String[] args) {
List<String> names = Arrays.asList("Brian", "Albert", "Roger");
for (Person person : peopleFromNames(names)) {
System.out.println(person.name);
}
}
}
do you mean using of delegates something like below
public class Test {
private static class Person{
private final String name;
Person(String name){
this.name = name;
}
#Override
public String toString() {
return return name;
}
}
private interface Printer {
void print(Object object);
}
public static void main(String[] args) {
final String[] names = {"one", "two", "three"};
final ArrayList<Person> people = construct(names, new Printer() {
#Override
public void print(Object object) {
System.out.println(object.toString());
}
});
}
private static ArrayList<Person> construct(String[] names, Printer printer) {
ArrayList<Person> people = new ArrayList<Person>();
for (String name : names) {
printer.print(new Person(name));
}
return people;
}
}
It's Possible.
Check these Project for Java-yield , yield4Java, infomancers
If you're using this just once in your entire code, You're better off choosing a method from the other answers.
Return a list of the new objects.

Categories