Converting Java Collection of some class to Collection of String - java

Assume a class (for instance URI) that is convertable to and from a String using the constructor and toString() method.
I have an ArrayList<URI> and I want to copy it to an ArrayList<String>, or the other way around.
Is there a utility function in the Java standard library that will do it? Something like:
java.util.collections.copy(urlArray,stringArray);
I know there are utility libraries that provide that function, but I don't want to add an unnecessary library.
I also know how to write such a function, but it's annoying to read code and find that someone has written functions that already exist in the standard library.

I know you don't want to add additional libraries, but for anyone who finds this from a search engine, in google-collections you might use:
List<String> strings = Lists.transform(uris, Functions.toStringFunction());
one way, and
List<String> uris = Lists.transform(strings, new Function<String, URI>() {
public URI apply(String from) {
try {
return new URI(from);
} catch (URISyntaxException e) {
// whatever you need to do here
}
}
});
the other.

No, there is no standard JDK shortcut to do this.

Have a look at commons-collections:
http://commons.apache.org/collections/
I believe that CollectionUtils has a transform method.

Since two types of collections may not be compatible, there is no built-in method for converting one typed collection to another typed collection.

Try:
public ArrayList<String> convert(ArrayList<URI> source) {
ArrayList<String> dest=new ArrayList<String>();
for(URI uri : source)
dest.add(source.toString());
return dest;
}
Seriously, would a built-in API offer a lot to that?
Also, not very OO. the URI array should probably be wrapped in a class. The class might have a .asStrings() method.
Furthermore you'll probably find that you don't even need (or even want) the String collection version if you write your URI class correctly. You may just want a getAsString(int index) method, or a getStringIterator() method on your URI class, then you can pass your URI class in to whatever method you were going to pass your string collection to.

Related

Java 8 streams and varargs

According to Effective Java 2nd Ed, when you want to write a method signature that allows for varargs but still enforces that you have one element minimum at compile-time you should write the method signature this way:
public void something(String required, String ... additional) {
//... do what you want to do
}
If I want to stream all these elements, I've been doing something like this:
public void something(String required, String ... additional) {
Stream<String> allParams =
Stream.concat(Stream.of(required), Stream.of(additional));
//... do what you want to do
}
This feels really inelegant and wasteful, especially because I'm creating a stream of 1 and concatenating it with another. Is there a cleaner way to do this?
Here is a way for doing it without creating two Streams, although you might not like it.
Stream.Builder<String> builder = Stream.<String>builder().add(required);
for (String s : additional) {
builder.add(s);
}
Stream<String> allParams = builder.build();
There is nothing wrong with the composed streams. These objects are lightweight as they only refer to the source data but don’t copy data like array contents. The cost of such lightweight object might only be relevant if the actual payload is very small as well. Such scenarios can be handled with specialized, semantically equivalent overloads:
public void something(String required, String ... additional) {
somethingImpl(Stream.concat(Stream.of(required), Stream.of(additional)));
}
public void something(String required) {
somethingImpl(Stream.of(required));
}
public void something(String required, String second) {
somethingImpl(Stream.of(required, second));
}
private void somethingImpl(Stream<String> allParams) {
//... do what you want to do
}
so in the case of only one argument you’re not only saving Stream instances but also the varargs array (similar to Stream.of’s overload). This is a common pattern, see for example the EnumSet.of overloads.
However, in a lot of cases even these simple overloads are not necessary and might be considered premature optimization (libraries like the JRE offer them as it’s otherwise impossible for an application developer to add them if ever needed). If something is part of an application rather than a library you shouldn’t add them unless a profiler tells you that there’s a bottleneck caused by that parameter processing.
If you're willing to use Guava, you may Lists.asList(required, additional).stream(). The method was created to ease that varargs with minimum requirement idiom.
A side note, I consider the library really useful, but of course it's not a good idea to add it just because of that. Check the docs and see if it could be of more use to you.
Unfortunately, Java can be quite verbose. But another option to alleviate that is to simply use static imports. In my opinion, it does not make your code less clear since every method is stream-related.
Stream<String> allParams =
concat(of(required), of(additional));
Third-party extensions to Stream API like my StreamEx or jOOλ provide methods like append or prepend which allow you to do this in more clean way:
// Using StreamEx
Stream<String> allParams = StreamEx.of(required).append(additional);
// Using jOOL
Stream<String> allParams = Seq.of(required).append(additional);

How can implementation know if an input parameter is mutable?

For example, some method has the next implementation:
void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
excludedCategories.remove(1L);
}
}
And it's called in the next way:
setExcludedCategories(Array.asList(1L, 2L, 3L));
Of course, it will lead ot an exception java.lang.UnsupportedOperationException when it will try to remove item.
The question: how can I modify this code to be sure that the input parameter excludedCategories supports remove?
UPD:
Thanks for answers. Let's summarize results:
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Catch the UnsupportedOperationException.
Specify in the JavaDoc that a caller mustn't pass an immutable list - anybody read the JavaDoc? When something doesn't work only :)
Don't use Arrays.asList() in a caller's code - that's an option, if you an owner of this code, but anyway you should know if this concrete method allows immutable or not (see 3).
It seems the second variant is the only way to resolve this problem.
How can I modify this code to be sure that the input parameter excludedCategories supports remove?
In the general case, you can't. Given an arbitrary class that implements the List API, you cannot tell (statically or dynamically) if the optional methods are supported.
You can use instanceof tests to check if the class of the list is known to implement the method or to not implement it. For example ArrayList and LinkedList do, but Collections.UnmodifiableList does not. The problem is that your code could encounter list classes that your tests don't cover. (Especially if it is a library that is intended to be reusable in other peoples applications.)
You could also try to test the behavior of previously unknown classes; e.g. create a test instance, try a remove to see what happens, and record the behavior in a Map<Class, Boolean>. There are two problems with this:
You may not be able to (correctly) instantiate the list class to test it.
The behavior could depend on how you instantiate the class (e.g. constructor parameters) or even on the nature of the element you are trying to remove ... though the latter is pushing the boundary of plausibility.
In fact, the only completely reliable approach is to call the method and catch the exception (if it is thrown) each and every time.
In short, you can't know. If an object implements an interface (such as List) you can't know if it will actually do what is expected for all of the methods. For instance Collections.unmodifiableList() returns a List that throws UnsupportedOperationException. It can't be filtered out via the method signature if you want to be able to get other List implementations.
The best you can do is to throw IllegalArgumentException for known subtypes that don't support what you want. And catch UnsupportedOperationException for other types of cases. But really you should javadoc your method with what is required and that it throws IllegalArgumentException in other cases.
That depends somewhat on what you're trying to do. In your posted example for example you could just catch the UnsupportedOperationException and do something else instead.
This assumes that you can assume that non-mutable containers will throw that on every attempt to modify the container and will do so without side effects (that is they are indeed non-mutable).
In other cases where your code has other side effects than trying to modify the container you will have to make sure these doesn't happen before knowing that you can modify the container.
You can catch the exception in an utility class like in the example below (as others mentioned). Bad thing is you have to do insert/delete to test if there will be exception. You can not use instanceof since all Collections.Unmodifiablexxx classes have default access.
CollectionUtils:
import java.util.List;
public class CollectionUtils {
public <T> boolean isUnmodifiableList(List<T> listToCheck) {
T object = listToCheck.get(0);
try {
listToCheck.remove(object);
} catch (UnsupportedOperationException unsupportedOperationException) {
return true;
}
listToCheck.add(0, object);
return false;
}
}
Main:
import java.util.Arrays;
import java.util.List;
public class Main {
private static final CollectionUtils COLLECTION_UTILS = new CollectionUtils();
public static void main(String[] args) {
setExcludedCategories(Arrays.asList(1L, 2L, 3L));
}
private static void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
if(!COLLECTION_UTILS.<Long>isUnmodifiableList(excludedCategories)){
excludedCategories.remove(1L);
}
}
}
}
Arrays.asList(T... a) returns the List<java.util.Arrays.ArrayList<E>> which is an immutable list. To get your code working just wrap the result with java.util.ArrayList<T> like shown below
setExcludedCategories(new ArrayList<Long>(Arrays.asList(1L, 2L, 3L)));
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Thats actually the preferred way to do things. "A lot of useless memory" isn't a lot in most practical situations, certainly not in your cited exampled.
And ignoring that, its the only robust and inutitively understood idiom.
The only workable alternative would be to explicitly change the name of your method (thus communicating its behavior better), form the example you show, name it "removeExcludedCategories" if its meant to modify the argument list (but not an objects state).
Otherwise if it is meant as a bulk-setter, you're out of luck, there is no commonly recognized naming idiom that clearly communicates that the argument collection is directly incorporated into the state of an object (its dangerous also because the objects state can then be altered without the object knowing about it).
Also, only marginally related, I would design not an exclusion list, but an exclusion set. Sets are conceptually better suited (no duplicates) and there are set implementations that have far better runtime complexity for the most commonly asked question: contains().

Is there a way in Java to pass multiple parameter pairs to a method?

Pretty new to Java
I would like to be able to use a method in following sort of way;
class PairedData {
String label;
Object val:
}
public void myMethod(String tablename, PairedData ... pD) {
/*
insert a record into a table -tablename with the various fields being
populated according to the information provided by the list of
PairedData objects
*/
}
myMethod("firststring",{"field1",Date1},{"field2",12},{"field3","aString"});
I realise the syntax is not valid but I hope it gives the gist of what I would like to do.
What I am trying to do is to directly pass the data rather than populate the instances of the class and then pass those. Is that possible or am I just trying to break a whole lot of OOPs rules?
No, what you're trying to do really isn't possible. It looks to me like it would be much better to pass instances of your class to the method as opposed to doing something convoluted with arrays like that. Another answer suggested using an Object[] varargs parameter - that's probably the closest you'll get to achieving something like what you show in your example. Another alternative (and I think a better one) would be
public void myMethod(String tablename, String[] labels, Object[] vals) {
You could instantiate your class for each labels[i] and vals[i] (pairing them up) in those arrays. In other words, in your method you could have something like
pD = new PairedData[labels.length];
for (i = 0; i < labels.length; i++)
pD[i] = new PairedData(labels[i], vals[i]); // assuming you
// added this
// constructor
The method call example that you included would then be converted to
myMethod("firststring", new String[]{"field1", "field2", "field3"},
new Object[]{date1, 12, "aString"});
You can do this by using arrays of Object:
public void myMethod(String tableName, Object[] ...pairs)
and invoke this method in a such style:
myMethod("someTable", new Object[] {"field1", date1}, new Object[] {"field2", date2});
usually...
you would make a class that has variable in it for all the parameters.
then you would build an instance of that class and populate the values.
then you could use that class instance to pass those around.
if you want a whole bunch... then make a Collection (Map, HashMap, List etc.) and pass that.
Seems to be a good case for a future language extension if you ask me. But by slightly changing the way you call your method we should be able to get close ...
myMethod("someTable",
new PairedData("field1", date1),
new PairedData("field2", date2)
);
It’s more type-work, but it is probably the safest as it is typesafe and not error prone to matching pairs.
You would also be required to write your constructor for ‘PairedData(String label, Object val)‘ for which I advise to write multiple overloaded versions one for each type of val you plan to store.

How to create IN OUT or OUT parameters in Java

In PL/SQL (or many other languages), I can have IN OUT or OUT parameters, which are returned from a procedure. How can I achieve a similar thing in Java?
I know this trick:
public void method(String in, String[] inOut, String[] inOut2) {
inOut[0] = in;
}
Where the in parameter represents an IN parameter and the inOut parameter can hold a return value. The convention would be that String[] inOut is an array of inOut.length == 1.
That's kind of clumsy.
EDIT Feedback to answers: Other tricks include:
holder/wrapper classes, but I don't want to introduce any new types, callbacks, etc.
return values: I'd like a general solution. I.e. one with several IN OUT parameters involved.
wrapper for IN OUT parameter as a return value: That's a viable option, but still not so nice, because that wrapper would have to be generated somehow
Does anyone know a better way to achieve this generally? The reason I need a general solution is because I want to generate convenience source code from PL/SQL in a database schema.
My question would be: Why doesn't method return something? Rather than setting an in/out argument?
But assuming you absolutely, positively must have an in/out argument, which is a whole different question, then the array trick is fine. Alternately, it's not less clumsy, but the other way is to pass in an object reference:
public class Foo {
private String value;
public Foo(String v) {
this.value = v;
}
public String getValue() {
return this.value;
}
public void setValue(String v) {
this.value = v;
}
}
// ....
public void method(String in, Foo inOut) {
inOut.setValue(in);
}
(Or, of course, just make value public.) See? I said it wasn't less clumsy.
But I'd ask again: Can't method return something? And if it needs to return multiple things, can't it return an object instance with properties for those things?
Off-topic: This is one of the areas where I really like the C# approach. One of the arguments against in/out arguments is that they're unclear at the point where you're calling the function. So C# makes you make it clear, by specifying the keyword both at the declaration of the function and when calling it. In the absense of that kind of syntactic help, I'd avoid "simulating" in/out arguments.
Java copies anything you pass as an argument. If you pass a primitive, inside method you have copy of that primitive, and no modifications will affect the actual variable outside method. If you pass object, you pass copy of reference, which actually references to the original object. This is the way how you can propagate modifications to the context of something that called the method - by modifying the state of the object that the reference is 'pointing' to. See more on this: Does Java Pass by Value or by Reference?
There's no direct way. Other technique include:
Passing a holder object (a bit like your 1-ary array)
Using, e.g., an AtomicInteger
Passing a more useful object from a business perspective that happens to be mutable
A callback to a custom interface for receiving the result
If you think about it, the array trick is not dissimilar to passing a T* in C/C++

Creating a Generic CsvReader

I'm trying to create a simple class to read a csv file and store the contents in an
ArrayList<ArrayList<T>>.
I'm creating a generic class CsvReader so that I can handle data of different types: int, double, String. If I had, say, a csv file of doubles, I was imagining I would use my class like this:
//possible method 1
CsvReader<Double> reader = new CsvReader<Double>();
ArrayList<ArrayList<Double>> contents = reader.getContents();
//possible method 2
CsvReader reader = new CsvReader(Double.class);
ArrayList<ArrayList<Double>> contents = reader.getContents();
But method 1 won't work since type erasure prevents you from writing code like
rowArrayList.add(new T(columnStringValue));
But I can't even make the passing in a Double.class solution work. The problem is that what's really going on is that I need my class "parameterized" (in the general sense of that word, not the technical java generics sense) on a type with the following property: it has a ctor accepting a single String argument. That is, to create the row ArrayLists on, say, a Double csv file, I'd need to write:
StringTokenizer st = new StringTokenizer(line,",");
ArrayList<Double> curRow = new ArrayList<Double>();
while (st.hasMoreTokens()) {
curRow.add(new Double(st.nextToken());
}
Having passed in Double.class, I could get its String ctor using
Constructor ctor = c.getConstructor(new Class[] {String.class});
but this has two problems. Most importantly, this is a general constructor that will return a type Object, which I cannot then downcast into a Double. Second, I would be missing "type" checking on the fact that I am requiring my passed in class to have a String arg constructor.
My question is: How can I properly implement this general purpose CsvReader?
Thanks,
Jonah
I'm not sure a generic CSV reader would be this simple to use (and to create, by the way).
The first question that comes to my mind is: What if the CSV contains three columns: first an integer, then a string and finally a date? How would you use your generic CSV reader?
Anyway, lets suppose you want to create a CSV reader where all columns are of the same type. As you said, you can't parametrize a class on a type "that accepts a String as constructor". Java just doesn't allow that. The solution using reflection is a good start. But what if your class doesn't take a String as parameter in one of its constructors?
Here you can come with an alternative: a parser that would take your String and return an object of the correct type. Create a generic interface, and make some implementations for the type you want to crawl:
public interface Parser<T> {
T parse(String value);
}
And then, implement:
public class StringParser implements Parser<String> {
public String parse(String value) {
return value;
}
}
Then, you CSV reader can take a Parser as one of its parameters. Then, it can use this parser to convert each String into a Java object.
With this solution, you get rid of the not-so-pretty reflection your where using. And you can convert to any type, you just have to implement a Parser.
Your reader will look like this:
public CSVReader<T> {
Parser<T> parser;
List<T> getValues() {
// ...
}
}
Now, back at the problem where a CSV file can have multiple types, just improve your reader a little. All you need is a list of parsers (one per column) instead of one that parse all columns.
Hope that helps :-)
Creating a correct CVS reader might be more difficult than you thought. For example, in your code example, it will not work correctly under the following situation.
"Microsoft, Inc",1,2,3
Instead of 4 fields, what you will be getting is 5 fields based on
StringTokenizer st = new StringTokenizer(line,",");
What my suggestion is, use third party libraries implementation. For example
http://opencsv.sourceforge.net/
I use it in one of my application, and my application has been running for 3 years. So far so good.
If you are trying to do real work, I suggest you forget that and use Scanner.
If you are experimenting: I would make CsvReader an abstract class:
public abstract class CsvReader<T> {
...
// This is what you use in the rest of CsvReader
// to create your objects from the strings in the CSV
protected abstract T parse(String s);
...
}
And it would be used as:
CsvReader<Double> = new CsvReader<Double>() {
#Override protected Double parse(String s) {
return Double.valueOf(s);
}
};
...
Not perfect, but reasonable.
EDIT: It turns out that you can have it your way, though it looks a bit hackish. See Super Type Tokens. It would basically involve including the logic shown in the Super Type Tokens link in CsvReader to have avilable the class object corresponding to your element class.
I had a need to read a simple list of strings stored in the cells of a CSV file, and started searching for a Java solution. I found most open source CSV readers to be unnecessarily complicated for my purpose. (See https://agiletribe.purplehillsbooks.com/2012/11/23/the-only-class-you-need-for-csv-files/ for a comprehensive review).
Finally I found MKYong's code very effective. I had to adapt it for my purpose to read the whole CSV or TSV file and return it as a list of lists. Each element in the inner list represents one cell of the CSV. The code along with credites to MKYong can be found at:
https://github.com/ramanraja/CsvReader

Categories

Resources