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();
}
}
Related
I was notified that is possible to create "infinite" ArrayLists inside others, such as in the code below:
import java.util.ArrayList;
public class Main
{
public static void main(String[] args) {
ArrayList<ArrayList<ArrayList<ArrayList<ArrayList<Object>>>>> List = new ArrayList<ArrayList<ArrayList<ArrayList<ArrayList<Object>>>>>();
}
}
And I want know about how to iterate them (with foreach or other loop types)
You could try to traverse it like a composite:
public static void traverse(ArrayList<T> arg) {
arg.forEach(
(n) -> if (n instanceof ArrayList) {
traverse(n)
} else {
doStomething(n)
}
);
}
IMHO, if someone writes such structures - it's some kind of a maniac.
But still, you can follow this kind of pattern in order to traverse:
#Test
public void test4() {
List<String> list1 = new ArrayList<>();
list1.add("abc");
list1.add("def");
List<List<String>> list2 = new ArrayList<>();
list2.add(list1);
list2.stream().flatMap(Collection::stream).forEach(System.out::println);
}
```
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);
I would like to map a list to another one. The decision is to be made on all the elements of the first list. Here is how it would look like, in crappy code :
import java.lang.Math;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class HelloWorld
{
public static void main(String[] args)
{
MatchingClass myObject = new MatchingClass();
System.out.println(myObject.getMatchingEnums(Arrays.asList("param1", "param3", "param2")));
System.out.print(myObject.getMatchingEnums(Arrays.asList("param1", "param3", "param4")));
}
}
enum TheEnums {
elem1("param1", "param2"),
elem2("param1", "param3");
String[] parameters;
TheEnums (String... parameters){
this.parameters = parameters;
}
String[] getParams (){
return parameters;
}
}
// you can add other public classes to this editor in any order
public class MatchingClass
{
public List<TheEnums> getMatchingEnums (List<String> givenParameters) {
List<TheEnums> result = new ArrayList<>();
for (TheEnums theEnum : TheEnums.values()){
if (givenParameters.containsAll(Arrays.asList(theEnum.getParams()))){
result.add (theEnum);
}
}
return result;
}
}
This could be written better, but what I want to know is if we can use the Java 8 Stream to be able to do that.
Maybe using Collectors ?
Thanks.
For example:
class MatchingClass {
public List<TheEnums> getMatchingEnums(List<String> givenParameters) {
List<TheEnums> enumsList = Arrays.asList(TheEnums.values());
return enumsList.stream()
.filter(e -> givenParameters.containsAll(Arrays.asList(e.getParams())))
.collect(Collectors.toList());
}
}
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.
I'm writing an adapter framework where I need to convert a list of objects from one class to another. I can iterate through the source list to do this as in
Java: Best way of converting List<Integer> to List<String>
However, I'm wondering if there is a way to do this on the fly when the target list is being iterated, so I don't have to iterate through the list twice.
Java 8 way:
List<String> original = ...;
List<Wrapper> converted = original.stream().map(Wrapper::new).collect(Collectors.toList());
assuming Wrapper class has a constructor accepting a String.
My answer to that question applies to your case:
import com.google.common.collect.Lists;
import com.google.common.base.Functions
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = Lists.transform(integers, Functions.toStringFunction());
The transformed list is a view on the original collection, so the transformation happens when the destination List is accessed.
As an alternative to the iterator pattern, you can use a abstract generic mapper class, and only override the transform method:
create a generic collection mapper for any data type
[optional] create a library of methods that transform between different data types (and override the method)
use that library
the implementation:
// Generic class to transform collections
public abstract class CollectionTransformer<E, F> {
abstract F transform(E e);
public List<F> transform(List<E> list) {
List<F> newList = new ArrayList<F>();
for (E e : list) {
newList.add(transform(e));
}
return newList;
}
}
// Method that transform Integer to String
// this override the transform method to specify the transformation
public static List<String> mapIntegerToStringCollection(List<Integer> list) {
CollectionTransformer transformer = new CollectionTransformer<Integer, String>() {
#Override
String transform(Integer e) {
return e.toString();
}
};
return transformer.transform(list);
}
// Example Usage
List<Integer> integers = Arrays.asList(1,2);
List<String> strings = mapIntegerToStringCollection(integers);
This would be useful is you have to use transformations every time, encapsulating the process.
So you can make a library of collection mappers very easy.
If you are trying to get a list of elements within a list then use the below code.Here the list of objects contains attribute name and below gets you list of names from that list
inputList.stream().map(p -> p.getName()).collect(Collectors.toList());
You can write a mapping iterator that decorates an existing iterator and applies a function on it. In this case, the function transforms the objects from one type to another "on-the-fly".
Something like this:
import java.util.*;
abstract class Transformer<T, U> implements Iterable<U>, Iterator<U> {
public abstract U apply(T object);
final Iterator<T> source;
Transformer(Iterable<T> source) { this.source = source.iterator(); }
#Override public boolean hasNext() { return source.hasNext(); }
#Override public U next() { return apply(source.next()); }
#Override public void remove() { source.remove(); }
public Iterator<U> iterator() { return this; }
}
public class TransformingIterator {
public static void main(String args[]) {
List<String> list = Arrays.asList("1", "2", "3");
Iterable<Integer> it = new Transformer<String, Integer>(list) {
#Override public Integer apply(String s) {
return Integer.parseInt(s);
}
};
for (int i : it) {
System.out.println(i);
}
}
}
Lambdaj allows to do that in a very simple and readable way. For example, supposing you have a list of Integer and you want to convert them in the corresponding String representation you could write something like that;
List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
public String convert(Integer i) { return Integer.toString(i); }
});
Lambdaj applies the conversion function only while you're iterating on the result.
There is also a more concise way to use the same feature. The next example works supposing that you have a list of persons with a name property and you want to convert that list in an iterator of person's names.
Iterator<String> namesIterator = convertIterator(persons, on(Person.class).getName());
Pretty easy. Isn't it?
This Could be a solutions --> by using map
List<Employee> employee = Arrays.asList(new Emp(1, 100), new Emp(2, 200), new Emp(3, 300));
List<Employee> employeS = employee.stream()
.map(emp -> new Emp(emp.getId(), emp.getSalary * 100))
.collect(Collectors.toList());
employeS .stream() .forEach(s -> System.out.println("Id :" + s.getId() + " Salary :" + s.getSalary()));
That question does not iterate through the list twice. It just iterates once and by far is the only known method.
Also you could use some transformer classes in commons-collections of google-collections but they all do the same thing under the hood :) the following being one way
CollectionUtils.collect(collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer());
Well, you could create your own iterator wrapper class to do this. But I doubt that you would save much by doing this.
Here's a simple example that wraps any iterator to a String iterator, using Object.toString() to do the mapping.
public MyIterator implements Iterator<String> {
private Iterator<? extends Object> it;
public MyIterator(Iterator<? extends Object> it) {
this.it = it;
}
public boolean hasNext() {
return it.hasNext();
}
public String next() {
return it.next().toString();
}
public void remove() {
it.remove();
}
}
I think you would either have to create a custom List (implementing the List interface) or a custom Iterator. For example:
ArrayList<String> targetList = new ArrayList<String>();
ConvertingIterator<String> iterator = new ConvertingIterator<String>(targetList);
// and here you would have to use a custom List implementation as a source List
// using the Iterator created above
But I doubt that this approach would save you much.
Here's an on-the-fly approach. (There must be something already like this in the jdk; I just can't find it.)
package com.gnahraf.util;
import java.util.AbstractList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
/**
*
*/
public class Lists {
private Lists() { }
public static <U,V> List<V> transform(List<U> source, Function<U, V> mapper) {
return new ListView<U, V>(source, mapper);
}
protected static class ListView<U, V> extends AbstractList<V> {
private final List<U> source;
private final Function<U, V> mapper;
protected ListView(List<U> source, Function<U, V> mapper) {
this.source = Objects.requireNonNull(source, "source");
this.mapper = Objects.requireNonNull(mapper, "mapper");
}
#Override
public V get(int index) {
return mapper.apply(source.get(index));
}
#Override
public int size() {
return source.size();
}
}
}