I have the following situation:
public ArrayList<A> getMethods(){
return b.c.test();
}
So, my problem is that b.c.test() returns a value with Optional<A> as return type. But I need to return an ArrayList<A>.
So, I tried to cast it and rewrite it to :
public ArrayList<A> getMethods(){
return (ArrayList<A>)b.c.test();
}
But Eclipse says that such a cast from Optional<A> to ArrayList<A> is not possible.
How can I solve this problem?
I am presuming your intended semantic is 'if the value is present return a list with a single item, otherwise return an empty list.' In that case I would suggest something like the following:
ArrayList<A> result = new ArrayList<>();
b.c.test().ifPresent(result::add);
return result;
However I would suggest your return type should be List<A> rather than ArrayList<A> as that gives you the opportunity to change the type of list without changing the callers. It would also allow you to return Collections.EMPTY_LIST if the optional value is not present which is more efficient than creating an unnecessary ArrayList.
Update: there's now an easier option with Java 9:
b.c.test().stream().collect(Collectors.toList());
Update: and even easier option with Java 16:
b.c.test().stream().toList();
In this case, it is possible to not use streams at all:
public static <T> List<T> toList(Optional<T> opt) {
return opt.isPresent()
? Collections.singletonList(opt.get())
: Collections.emptyList();
}
Or, the same code using the functional API:
public static <T> List<T> toList(Optional<T> opt) {
return opt
.map(Collections::singletonList)
.orElseGet(Collections::emptyList);
}
I prefer the upper variant because I know for sure that it doesn't create any unnecessary objects on the Java heap.
If everyone insists on using streams for this issue, it should be more idiomatic than using ifPresent()
Unfortunately, Java 8 does not have a Optional.stream() method, so it is not possible to do:
optional.stream().collect(Collectors.toList());
see also: Using Java 8's Optional with Stream::flatMap
But in JDK 9, it will be added (and that code actually already runs on Java 9)
Optional<Integer> o = Optional.empty();
final List<Integer> list = o.stream().collect(Collectors.toList());
System.out.println(list);
return b.c.test()
.map(Arrays::asList).map(ArrayList::new)
.orElseGet(ArrayList::new);
If the optional has a value, it "maps" it to a List<A> with Arrays.asList and then to an ArrayList via the new ArrayList<A>(List<A>) constructor; otherwise it yields an empty ArrayList via the empty constructor.
This could be more explicitly written out as:
return b.c.test()
.map(value -> new ArrayList<A>(Arrays.asList(value)))
.orElseGet(() -> new ArrayList<A>());
With Java9, you can do this using the newly added Optional::stream API :
Optional<List<A>> list;
List<A> collect = list.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
Since Java 9
return b.c.test().stream()
.collect(toList());
import static java.util.stream.Collectors.toList;
Since Java 8
return b.c.test()
.map(List::of)
.orElse(emptyList());
import static java.util.Collections.emptyList;
If you're using Guava's Optional, you can do:
return new ArrayList<>(b.c.test().asSet());
This will extract the value from the Optional (if present) and add it to a new ArrayList.
If you're using Java 8, #sprinter's answer is what you need.
An Optional is a container object which may or may not contain a non-null value.
In ArrayList terms I would translate it as an array which has 0 or 1 members.
public ArrayList<A> getMethods(){
Optional<A> opt = b.c.test();
ArrayList<A> res = new ArrayList<>();
if ( opt.isPresent() )
res.add( opt.get() );
return res;
}
Related
Let's assume that we have a List of ExampleDTO that contains some fields, among others "name" field. Everytime I want to get a list of proper fields, in this case names, I write code as below:
private List<String> getNames(List<ExampleDTO> exampleDTOs) {
List<String> names = new ArrayList<String>();
for (ExampleDTO exampleDTO : exampleDTOs)
names.add(exampleDTO.getName());
return names;
}
...but I also noticed that this kind of code is repeating over and over again.
And the question is: Is there any smart method that would help me reduce amount of redundant code produced?
EDIT:
I'm using Java7 for my application.
With Java 7 you can use Guava's FluentIterable and Function:
List<ExampleDTO> exampleDTOs = ...;
List<String> names = FluentIterable.from(exampleDTOs)
.transform(new Function<ExampleDTO, String>() {
#Override
public String apply(ExampleDTO dto) {
return dto.getName();
}
})
.toList();
Note that, although the whole loop is expressed as a single expression, the performance is significantly worse than a loop, and it's very arguable if this is more readable.
I would stick to a simple loop until the upgrade to Java 8.
In one of the projects, I used to mark all such loops with special comments, so that all these places were easy to find when the upgrade to Java 8 was performed.
With Java 8 you could use Streams API:
List<ExampleDTO> exampleDTOs = ...;
List<String> names = exampleDTOs.stream()
.map(dto -> dto.getName())
.collect(Collectors.toList());
It could get even shorter if you don't necessarily need the list of names — in this case the .collect(Collectors.toList()) part could be removed.
For example, you can iterate over the list of names directly on the stream as follows:
exampleDTOs.stream()
.map(dto -> dto.getName())
.forEach(name -> System.out.println(name));
This would just print all the names, but you can replace the System.out.println(name) with anything else.
In java 8 you have a new interface called Function allowing you to map a value to get something else, the idea here would be to implement the same logic with Java 7.
So the function interface would be:
public interface Function<T, R> {
/**
* Applies this function to the given argument.
* #param t the function argument
* #return the function result
*/
R apply(T t);
}
and your method could be something like that:
private <R> List<R> getValues(List<ExampleDTO> exampleDTOs, Function<ExampleDTO, R> function) {
List<R> values = new ArrayList<>();
for (ExampleDTO exampleDTO : exampleDTOs)
values.add(function.apply(exampleDTO));
return values;
}
In your case you could use a private static final variable to define your function as an anonymous class, like this:
private static final Function<ExampleDTO, String> BY_NAME = new Function<ExampleDTO, String>() {
public String apply(ExampleDTO e) {
return e.getName();
}
}
Then calls getValues(exampleDTOs, BY_NAME)
I have multiple Set<String> that I need to merge into one Set<String>. How do I do this operation in Java? Note, I am using using the guava API as best as I can to help out. For example, I have 3 classes as follows.
public class One {
public static Set<String> SET = Sets.newHashSet("a","b","c");
}
public class Two {
public static Set<String> SET = Sets.newHashSet("a","d","e","f");
}
public class Three {
public static Set<String> SET = Sets.newHashSet("w","x","y","f");
}
Now, I need to merge any combination of these sets into one. For, example, I may need to merge
One.SET + Two.SET + Three.SET into one to produce { "a","b","c","d","e","f","w","x","y" },
One.SET + Three.SET into one to produce { "a","b","c","w","x","y","f" },
Two.SET + Three.SET into one to produce { "a","d","e","f","w","x","y" },
and so on
I created a method to merge an array of sets, Set<String>[], but that doesn't work (explained here by this SO post Creating an array of Sets in Java). Here's the code to merge. It works (compiles).
public static Set<String> immutableSetOf(Set<String>[] sets) {
Set<String> set = new HashSet<String>();
for(Set<String> s : sets) {
set.addAll(s);
}
return ImmutableSet.copyOf(set);
}
Here's the calling code; it doesn't work (doesn't compile).
Set<String> set = Utils.immutableSetOf(new Set<String>[] { One.SET, Two.SET });
So, I modified my merging method to operate on List<Set<String>> instead of Set<String>[]. Only the argument type changed, but I put it here for completeness.
public static Set<String> immutableSetOf(List<Set<String>> sets) {
Set<String> set = new HashSet<String>();
for(Set<String> s : sets) {
set.addAll(s);
}
return ImmutableSet.copyOf(set);
}
So, now my calling code looks like the following.
Set<String> set = Utils.immutableSetOf(
Lists.newArrayList(
One.SET, Two.SET));
This code does not compile, since Lists.newArrayList(...) is returning Set<String> and not List<Set<String>>. The method Lists.newArrayList(...) is overloaded, and the signature of the method that is used when I pass in sets is, List.newArrayList(Iterable<? extends E> elements).
So, the question is, how do I define a method to merge an arbitrary number of Set<String> while considering the calling code? I note that the compilation problems are on the calling code (not the merging method), but perhaps the solution also relates to the merging code?
Update: I also tried varargs but that produces its own warning (Is it possible to solve the "A generic array of T is created for a varargs parameter" compiler warning?). The merging method signature is now the following.
public static Set<String> immutableSetOf(Set<String>... sets)
The calling code is now the following, and I get "Type safety: A generic array of Set is created for a varargs parameter".
Set<String> set = Utils.immutableSetOf(One.SET, Two.SET);
Update: For the accepted answer, I did the following.
#SuppressWarnings("unchecked")
Set<String> set = Utils.immutableSetOf(Set[] { One.SET, Two.SET });
Recommend com.google.common.collect.Sets#union(set1, set2) to get the merge instead of Set.addAll under hood, since Guava is already in your dependencies.
Reason: it's view which is memory effective, and also unmodifiable.
plus: I should have post it as a comment, sorry.
How about creating a collection of your input sets, then using flatMap?
Set<String> allElements = ImmutableSet.of(
One.SET,
Two.SET,
Three.SET
).stream().flatMap(Collection::stream).collect(Collectors.toSet());
In your previous attempt, you had written
Set<String> set = Utils.immutableSetOf(new Set<String>[] { One.SET, Two.SET });
This does not work because, generics array creation is not allowed in java
Try this:
#SuppressWarnings("unchecked")
Set<String>[] mySet = new Set[] { One.SET, Two.SET };
Set<String> set = Utils.immutableSetOf(mySet);
The reason this works is because, we create a new Set[] without specifying the generics type and assign it to the reference Set[] mySet (since this is an unchecked operation, we have to add #SuppressWarnings("unchecked") to it)
You could use:
Set<String> set = immutableSetOf(Arrays.asList(One.SET, Two.SET));
Using your definition of immutableSetOf(List<Set<String>> sets). No warnings or suppressed warnings.
I'm thinking that FluentIterable (in 18.0 and above) can help here, specifically the append method.
With that, we need to define a convenient helper method - and yes, we're going to use varargs for this.
public <T extends Comparable<T>> Set<T> mergeSets(Set<T> initial,
Set<T>... rest) {
FluentIterable<T> result = FluentIterable.from(initial);
for(Set<T> set : rest) {
result = result.append(set);
}
return new TreeSet<>(result.toSet());
}
The resultant set here is in natural order. If you don't want a TreeSet and you don't want to mutate your collection afterwards, then omit the new TreeSet<> piece, and loosen the bound on T.
I have a List of object and the list is very big. The object is
class Sample {
String value1;
String value2;
String value3;
String value4;
String value5;
}
Now I have to search for a specific value of an object in the list. Say if value3=='three' I have to return those objects (My search is not always based on value3)
The list is
List<Sample> list = new ArrayList<Sample>();
What is the efficient way of doing it?
Thanks.
You can give a try to Apache Commons Collections.
There is a class CollectionUtils that allows you to select or filter items by custom Predicate.
Your code would be like this:
Predicate condition = new Predicate() {
boolean evaluate(Object sample) {
return ((Sample)sample).value3.equals("three");
}
};
List result = CollectionUtils.select( list, condition );
Update:
In java8, using Lambdas and StreamAPI this should be:
List<Sample> result = list.stream()
.filter(item -> item.value3.equals("three"))
.collect(Collectors.toList());
much nicer!
Using Java 8
With Java 8 you can simply convert your list to a stream allowing you to write:
import java.util.List;
import java.util.stream.Collectors;
List<Sample> list = new ArrayList<Sample>();
List<Sample> result = list.stream()
.filter(a -> Objects.equals(a.value3, "three"))
.collect(Collectors.toList());
Note that
a -> Objects.equals(a.value3, "three") is a lambda expression
result is a List with a Sample type
It's very fast, no cast at every iteration
If your filter logic gets heavier, you can do list.parallelStream() instead of list.stream() (read this)
Apache Commons
If you can't use Java 8, you can use Apache Commons library and write:
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
Collection result = CollectionUtils.select(list, new Predicate() {
public boolean evaluate(Object a) {
return Objects.equals(((Sample) a).value3, "three");
}
});
// If you need the results as a typed array:
Sample[] resultTyped = (Sample[]) result.toArray(new Sample[result.size()]);
Note that:
There is a cast from Object to Sample at each iteration
If you need your results to be typed as Sample[], you need extra code (as shown in my sample)
Bonus: A nice blog article talking about how to find element in list.
If you always search based on value3, you could store the objects in a Map:
Map<String, List<Sample>> map = new HashMap <>();
You can then populate the map with key = value3 and value = list of Sample objects with that same value3 property.
You can then query the map:
List<Sample> allSamplesWhereValue3IsDog = map.get("Dog");
Note: if no 2 Sample instances can have the same value3, you can simply use a Map<String, Sample>.
I modifie this list and add a List to the samples try this
Pseudocode
Sample {
List<String> values;
List<String> getList() {
return values}
}
for(Sample s : list) {
if(s.getString.getList.contains("three") {
return s;
}
}
As your list is an ArrayList, it can be assumed that it is unsorted. Therefore, there is no way to search for your element that is faster than O(n).
If you can, you should think about changing your list into a Set (with HashSet as implementation) with a specific Comparator for your sample class.
Another possibility would be to use a HashMap. You can add your data as Sample (please start class names with an uppercase letter) and use the string you want to search for as key. Then you could simply use
Sample samp = myMap.get(myKey);
If there can be multiple samples per key, use Map<String, List<Sample>>, otherwise use Map<String, Sample>. If you use multiple keys, you will have to create multiple maps that hold the same dataset. As they all point to the same objects, space shouldn't be that much of a problem.
You can filter the list:
list.stream().filter(
sample -> sample.getValue4().equals("4")
).forEach(System.out::println)
I propose for+if.
Object result;
for (Object o: objects){
if (o.value3.equals("three")){
result=o;
break;
}
}
no streams, no guavas, I think it's simple.
Let's say I have a bean like below.
class Customer{
private String code;
private String name;
private Integer value;
//getters setters omitted for brevity
}
Then from a method I get a List<Customer> back. Now let's say I want to get a list of all member "name" from the List. Obviously I can traverse and build a List<String> of element "name" myself.
However, I was wondering if there is a short cut or more effiecient way to this technique that anyone knows . For instance, if I want to get a list of all keys in a Map object I get do map.keySet(). Something along that line is what I am trying to find out.
Guava has Lists.transform that can transform a List<F> to a List<T>, using a provided Function<F,T> (or rather, Function<? super F,? extends T>).
From the documentation:
public static <F,T>
List<T> transform(
List<F> fromList,
Function<? super F,? extends T> function
)
Returns a list that applies function to each element of fromList. The returned list is a transformed view of fromList; changes to fromList will be reflected in the returned list and vice versa.
The function is applied lazily, invoked when needed.
Similar live-view transforms are also provided as follows:
Iterables.transform (Iterable<F> to Iterable<T>)
Iterators.transform (Iterator<F> to Iterator<T>)
Collections2.transform (Collection<F> to Collection<T>)
Maps.transformValues (Map<K,V1> to Map<K,V2>)
Looks like you're looking for the Java equivalent of Perl's map function. This kind of thing might be added to the collections library once (if) Java receives closures. Until then, I think this is the best you can do:
List<String> list = new ArrayList<String>(customers.size());
for ( Customer c : customers ) {
list.add(c.getName());
}
You could also write a map function that uses a simple interface to provide the mapping function. Something like this:
public interface Transform<I, O> {
O transform(I in);
}
public <I, O> List<O> map(Collection<I> coll, Transform<? super I, ? extends O> xfrm) {
List<O> list = new ArrayList<O>(coll.size());
for ( I in : coll ) {
list.add(xfrm.transform(in));
}
return list;
}
could use something like this:
http://code.google.com/p/lambdaj/
I think this is something that you would have to code yourself, in a loop.
You can use LambdaJ's Converter interface and have the following line:
List<String> customerNames = convert(customerList, new Converter<Customer,String>() {
public String convert(Customer customer) {
return customer.getName();
}
});
You need to use a loop, but the function you're looking for is called map in functional languages. It's possible to implement map in Java, although it tends to be fairly inelegant; here's the version I implemented ages ago in my "stuff Java should have but for some reason doesn't" library:
public interface MapFunction<T, U> {
public U map(T source);
}
public static <T, U> U[] map(T[] objects, MapFunction<T, U> f) {
if(objects.length == 0) {throw new IllegalArgumentException("Can't map onto an empty array");}
#SuppressWarnings("unchecked") U[] rtn = (U[])Array.newInstance(f.map(objects[0]).getClass(), objects.length);
for(int i = 0; i < objects.length; i++)
rtn[i] = f.map(objects[i]);
return rtn;
}
Using that, you could do:
List<Customer> list = yourFunction();
List<String> names = Arrays.asList(map(list.toArray(new Customer[0]), new MapFunction<Customer, String>() {
public String map(Customer c) {
return c.getName();
}
}));
You could naturally change map to take collections instead of arrays, which would eliminate the need for Arrays.asList and List.toArray
Using Guava, you can use a Function along with Iterables.transform, Collections2.transform or Lists.transform to create an Iterable, Collection or List respectively.
Iterable<String> names = Iterables.transform(customers,
new Function<Customer, String>() {
public String apply(Customer from) {
return from.getName();
}
});
The returned Iterable is lazy and applies the function to the underlying list as you iterate through it. For a List<String> containing the names, you could use:
List<String> names = Lists.transform(...);
or
ImmutableList<String> names = ImmutableList.copyOf(Iterables.transform(...));
Of course, writing out the anonymous inner class Function implementation each time you want to do this is ugly and verbose, so you may want to make the Function a constant available from the Customer class, called Customer.NAME for instance.
Then the transformation looks much nicer (with static imports especially):
for (String name : transform(customers, Customer.NAME)) { ... }
I also wrote about using interfaces for particular properties of objects (such as name here) to help with consolidating such functions on my blog here.
.... is there a short cut or more efficient way
So, are you looking for a more efficient way to do this:
List<String> names = new ArrayList<String>();
for( Customer customer : yourCustomerList ) {
names.add( customer.getName() );
}
?!!!!
Or just a different way?
All the previous answer are not really more efficient in terms of runtime nor coding. They are however more flexible without a doubt.
Another alternative would be to include Scala Groovy in your Java code and use this:
list.map( _.name )
list.collect { it.name }
If compiled, Groovy classes may be used from Java, or you can plug in them as an script.
Here's a sample for the given Customer class using Groovy as script.
List<Customer> customers = Arrays.asList( new Customer[]{
new Customer("A","123",1),
new Customer("B","456",2),
new Customer("C","789",3),
new Customer("D","012",4)
});
setVariable(customers, "list");
evaluate("names = list.collect { it.name } ");
List<String> names = (List<String>) getVariable("names");
System.out.println("names = " + names);
Output:
names = [A, B, C, D]
note: I extracted method for readability, but you can see them below
But, again that's just different, not really more efficient than the regular for loop.
Here's the complete source code. To run it you just need Java1.6 and Groovy in the classpath.
I have a list of integers, List<Integer> and I'd like to convert all the integer objects into Strings, thus finishing up with a new List<String>.
Naturally, I could create a new List<String> and loop through the list calling String.valueOf() for each integer, but I was wondering if there was a better (read: more automatic) way of doing it?
Using Google Collections from Guava-Project, you could use the transform method in the Lists class
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 List returned by transform is a view on the backing list - the transformation will be applied on each access to the transformed list.
Be aware that Functions.toStringFunction() will throw a NullPointerException when applied to null, so only use it if you are sure your list will not contain null.
Solution for Java 8. A bit longer than the Guava one, but at least you don't have to install a library.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
//...
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = integers.stream().map(Object::toString)
.collect(Collectors.toList());
For Java 11,
List<String> strings = integers.stream().map(Object::toString)
.collect(Collectors.toUnmodifiableList());
Still no map convenience method, really?
As far as I know, iterate and instantiate is the only way to do this. Something like (for others potential help, since I'm sure you know how to do this):
List<Integer> oldList = ...
/* Specify the size of the list up front to prevent resizing. */
List<String> newList = new ArrayList<>(oldList.size());
for (Integer myInt : oldList) {
newList.add(String.valueOf(myInt));
}
What you're doing is fine, but if you feel the need to 'Java-it-up' you could use a Transformer and the collect method from Apache Commons, e.g.:
public class IntegerToStringTransformer implements Transformer<Integer, String> {
public String transform(final Integer i) {
return (i == null ? null : i.toString());
}
}
..and then..
CollectionUtils.collect(
collectionOfIntegers,
new IntegerToStringTransformer(),
newCollectionOfStrings);
The source for String.valueOf shows this:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Not that it matters much, but I would use toString.
Instead of using String.valueOf I'd use .toString(); it avoids some of the auto boxing described by #johnathan.holland
The javadoc says that valueOf returns the same thing as Integer.toString().
List<Integer> oldList = ...
List<String> newList = new ArrayList<String>(oldList.size());
for (Integer myInt : oldList) {
newList.add(myInt.toString());
}
Here's a one-liner solution without cheating with a non-JDK library.
List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", "));
Another Solution using Guava and Java 8
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number));
To the people concerned about "boxing" in jsight's answer: there is none. String.valueOf(Object) is used here, and no unboxing to int is ever performed.
Whether you use Integer.toString() or String.valueOf(Object) depends on how you want to handle possible nulls. Do you want to throw an exception (probably), or have "null" Strings in your list (maybe). If the former, do you want to throw a NullPointerException or some other type?
Also, one small flaw in jsight's response: List is an interface, you can't use the new operator on it. I would probably use a java.util.ArrayList in this case, especially since we know up front how long the list is likely to be.
List<String> stringList = integerList.stream().map((Object s)->String.valueOf(s)).collect(Collectors.toList())
Not core Java, and not generic-ified, but the popular Jakarta commons collections library has some useful abstractions for this sort of task. Specifically, have a look at the collect methods on
CollectionUtils
Something to consider if you are already using commons collections in your project.
A slightly more concise solution using the forEach method on the original list:
List<Integer> oldList = Arrays.asList(1, 2, 3, 4, 5);
List<String> newList = new ArrayList<>(oldList.size());
oldList.forEach(e -> newList.add(String.valueOf(e)));
#Jonathan: I could be mistaken, but I believe that String.valueOf() in this case will call the String.valueOf(Object) function rather than getting boxed to String.valueOf(int). String.valueOf(Object) just returns "null" if it is null or calls Object.toString() if non-null, which shouldn't involve boxing (although obviously instantiating new string objects is involved).
I think using Object.toString() for any purpose other than debugging is probably a really bad idea, even though in this case the two are functionally equivalent (assuming the list has no nulls). Developers are free to change the behavior of any toString() method without any warning, including the toString() methods of any classes in the standard library.
Don't even worry about the performance problems caused by the boxing/unboxing process. If performance is critical, just use an array. If it's really critical, don't use Java. Trying to outsmart the JVM will only lead to heartache.
An answer for experts only:
List<Integer> ints = ...;
String all = new ArrayList<Integer>(ints).toString();
String[] split = all.substring(1, all.length()-1).split(", ");
List<String> strs = Arrays.asList(split);
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.
You can't avoid the "boxing overhead"; Java's faux generic containers can only store Objects, so your ints must be boxed into Integers. In principle it could avoid the downcast from Object to Integer (since it's pointless, because Object is good enough for both String.valueOf and Object.toString) but I don't know if the compiler is smart enough to do that. The conversion from String to Object should be more or less a no-op, so I would be disinclined to worry about that one.
Just for fun, a solution using the jsr166y fork-join framework that should in JDK7.
import java.util.concurrent.forkjoin.*;
private final ForkJoinExecutor executor = new ForkJoinPool();
...
List<Integer> ints = ...;
List<String> strs =
ParallelArray.create(ints.size(), Integer.class, executor)
.withMapping(new Ops.Op<Integer,String>() { public String op(Integer i) {
return String.valueOf(i);
}})
.all()
.asList();
(Disclaimer: Not compiled. Spec is not finalised. Etc.)
Unlikely to be in JDK7 is a bit of type inference and syntactical sugar to make that withMapping call less verbose:
.withMapping(#(Integer i) String.valueOf(i))
This is such a basic thing to do I wouldn't use an external library (it will cause a dependency in your project that you probably don't need).
We have a class of static methods specifically crafted to do these sort of jobs. Because the code for this is so simple we let Hotspot do the optimization for us. This seems to be a theme in my code recently: write very simple (straightforward) code and let Hotspot do its magic. We rarely have performance issues around code like this - when a new VM version comes along you get all the extra speed benefits etc.
As much as I love Jakarta collections, they don't support Generics and use 1.4 as the LCD. I am wary of Google Collections because they are listed as Alpha support level!
I didn't see any solution which is following the principal of space
complexity. If list of integers has large number of elements then it's
big problem.
It will be really good to remove the integer from the List<Integer> and free
the space, once it's added to List<String>.
We can use iterator to achieve the same.
List<Integer> oldList = new ArrayList<>();
oldList.add(12);
oldList.add(14);
.......
.......
List<String> newList = new ArrayList<String>(oldList.size());
Iterator<Integer> itr = oldList.iterator();
while(itr.hasNext()){
newList.add(itr.next().toString());
itr.remove();
}
I just wanted to chime in with an object oriented solution to the problem.
If you model domain objects, then the solution is in the domain objects. The domain here is a List of integers for which we want string values.
The easiest way would be to not convert the list at all.
That being said, in order to convert without converting, change the original list of Integer to List of Value, where Value looks something like this...
class Value {
Integer value;
public Integer getInt()
{
return value;
}
public String getString()
{
return String.valueOf(value);
}
}
This will be faster and take up less memory than copying the List.