ArrayStoreException in array of Consumers<X> - java

I’m storing references to BiConsumers<Integer, X> adapted to Consumer<Integer>:
public void setConsumer(BiConsumer<Integer, X> consumer) {
fieldConsumer = integer -> consumer.accept(integer, fieldSubject);
}
But I need 2 of them, so I changed the code to use an array:
private Consumer<Integer>[] fieldConsumers;
public MyClass(int numberOfConsumers) {
Consumer<Integer> consumer = integer -> {};
fieldConsumers= (Consumer<Integer>[]) Array.newInstance(consumer.getClass(), numberOfObservers);
}
public void addConsumer(int consumerIndex, BiConsumer<Integer, X> consumer) {
// Offending line
fieldConsumers[consumerIndex] = responseType-> consumer.accept(responseType, fieldSubject);
}
So that the callback can be triggered with a:
for (Consumer<Integer> consumer: fieldConsumers) {
consumer.accept(responseType);
}
I got the error:
java.lang.ArrayStoreException:
on this line:
fieldConsumers[consumerIndex] = responseType-> consumer.accept(responseType, fieldSubject);
Now, If you are still reading this, I have one more question:
Am I still holding reference to outside Consumers if I do it this way, as opposed to using the old fieldConsumers.add(consumer) where fieldConsumers is a List<BiConsumer<Integer, X>> ?

You used Array.newInstance(consumer.getClass(), numberOfObservers) to create the Consumer<Integer>[] array. But consumer.getClass() returns the actual class of the object you’re invoking the method on, which is always an implementation class of the interface. An array of this element type can only hold objects of the same concrete class, not arbitrary implementations of the interface.
This is not different to, e.g.
CharSequence cs = "hello";
CharSequence[] array = (CharSequence[]) Array.newInstance(cs.getClass(), 1);
array[0] = new StringBuilder();
Here, cs has the type CharSequence and the reflective array creation appears to create an array of type CharSequence[], so storing a StringBuilder should be possible. But since cs.getClass() returns the actual implementation class String, the array is actually of type String[], hence, the attempt to store a StringBuilder produces an ArrayStoreException.
In case of lambda expressions, things get slightly more complicated, as the actual implementation classes of the functional interface are provided at runtime and intentionally unspecified. You used the lambda expression integer -> {} for the array creation in the constructor, which evaluated to a different implementation class than the responseType-> consumer.accept(responseType, fieldSubject) within the addConsumer method, in this particular runtime.
This behavior is in line with this answer describing the behavior of the most commonly used environment. Still, other implementations could exhibit different behavior, e.g. evaluate to the same implementation class for a particular functional interface for all lambda expressions. But it’s also possible that multiple evaluations of the same lambda expression produce different classes.
So the fix is to use the intended interface element type, e.g.
fieldConsumers=(Consumer<Integer>[])Array.newInstance(Consumer.class, numberOfObservers);
But there is no need for a reflective array creation at all. You can use:
fieldConsumers = new Consumer[numberOfObservers];
You can not write new Consumer<Integer>[numberOfObservers], as generic array creation is not allowed. That’s why the code above uses a raw type. Using Reflection instead wouldn’t improve the situation, as it is an unchecked operation in either case. You might have to add #SuppressWarnings for it. The cleaner alternative is to use a List<Consumer<Integer>>, as it shields you from the oddities of arrays and generics.
It’s not clear what you mean with “reference to outside Consumers” here. In either case, you have references to Consumer implementations capturing references to BiConsumer implementations you received as arguments to addConsumer.

Related

method reference vs lambda expression

I want to replace lambda expression by method reference in the below example :
public class Example {
public static void main(String[] args) {
List<String> words = Arrays.asList("toto.", "titi.", "other");
//lambda expression in the filter (predicate)
words.stream().filter(s -> s.endsWith(".")).forEach(System.out::println);
}
}
I want to write a something like this :
words.stream().filter(s::endsWith(".")).forEach(System.out::println);
is it possible to transform any lambda expression to method reference.
There is no way “to transform any lambda expression to method reference”, but you can implement a factory for a particular target type, if this serves recurring needs:
public static <A,B> Predicate<A> bind2nd(BiPredicate<A,B> p, B b) {
return a -> p.test(a, b);
}
with this, you can write
words.stream().filter(bind2nd(String::endsWith, ".")).forEach(System.out::println);
but actually, there’s no advantage. Technically, a lambda expression does exactly what you want, there’s the minimum necessary argument transformation code, expressed as the lambda expression’s body, compiled into a synthetic method and a method reference to that synthetic code. The syntax
s -> s.endsWith(".") also is already the smallest syntax possible to express that intent. I doubt that you can find a smaller construct that would still be compatible with the rest of the Java programming language.
You can use selectWith() from Eclipse Collections. selectWith() takes a Predicate2 which takes 2 parameters instead of a Predicate. The second parameter to selectWith() gets passed as the second parameter to the Predicate2 every time it's called, once per item in the iterable.
MutableList<String> words = Lists.mutable.with("toto.", "titi.", "other");
words.selectWith(String::endsWith, ".").each(System.out::println);
By default Eclipse Collections is eager, if you want to iterate lazily then you can use asLazy()
words.asLazy().selectWith(String::endsWith, ".").each(System.out::println);
If you can't change from List:
List<String> words = Arrays.asList("toto.", "titi.", "other");
ListAdapter.adapt(words).selectWith(String::endsWith, ".").each(System.out::println);
Eclipse Collections' RichIterable has several other *With methods which work well with method references, including rejectWith(), partitionWith(), detechWith(), anySatisfyWith(), allSatisfyWith(), noneSatisfyWith(), collectWith()
Note: I am a contributor to Eclipse Collections.

Java Best Practices - Returning an Object vs. a Generic

I'm using Generics for the first time for a school project and I have come across a philosophical dilemma regarding whether to return objects or my declared generic element in my methods.
My OCD is telling me that I need to always return the known type but I'm finding that doing so creates some downstream annoyances when I feed primitive datatypes into my class (and, of course, for this project I'm only ever feeding primitives into this class).
Here's an example of what I mean:
public class DansPriorityQueue<E extends Comparable>
{
private ArrayList<E> tree;
//Here's a method that returns an object
public Object peek() {
return tree.get(0);
}
//Here's a method that returns the generic type
public E peek() {
return tree.get(0);
}
(As an FYI.. I'm required to implement this JDK class myself but I am fortunately not required to implement the same interfaces that the real PriorityQueue does so I do have a choice as to whether I want to use the Object or the generic)
My Issue
It makes me feel a little dirty but I'm tempted just to return an Object rather than my E generic element on these methods because when I return E, JUnit forces me to cast my integer values:
DansPriorityQueue<Integer> dpq = new DansPriorityQueue<Integer>();
dpq.add(1);
assertEquals("Expected different value", (Integer) 1, dpq.peek());
When I return an object on the other hand, the auto-boxing doesn't force me cast my primitive value.
Here's a more eloquent description of the issue I've been facing:
http://www.aschroder.com/2009/10/php-1-java-0-the-method-assertequalsobject-object-is-ambiguous-for-the-type/
------------EDIT----------------
Here's the actual error I receive when I return the generic type and fill my list with the autoboxed Integer object without the cast above: The method assertEquals(String, Object, Object) is ambiguous for the type DansPriorityQueueTest
--------- END EDIT--------------
Questions
Can anyone tell me why I should or should not return an object as opposed to the generic element I'm working with? Both seem to have upsides and downsides... what's the best practice?
I know vaguely that returning an Object can cause some casting issues later on but I've not yet run into them... does anyone have a specific example of how this can be dangerous?
In the JDK, I've noticed that many of the Collections methods return Object by default. Is this because Generics was introduced in a later version of Java or was this a conscious decision by Sun Systems?
Can anyone tell me why I should or should not return an object as opposed to the generic element I'm working with? Both seem to have upsides and downsides... what's the best practice?
It depends. In a case like this you'd want to generic type - otherwise what's the point of defining generic type for the class?
I know vaguely that returning an Object can cause some casting issues later on but I've not yet run into them... does anyone have a specific example of how this can be dangerous?
Sure!
DansPriorityQueue<String> queue = new DansPriorityQueue<String>();
//add items
Float f = (Float)queue.getObject(); //uh-oh! this compiles but will fail
Float f = queue.getObject(); //generic type, fails during compile
In the JDK, I've noticed that many of the Collections methods return Object by default. Is this because Generics was introduced in a later version of Java or was this a conscious decision by Sun Systems?
It's due to backward compatibility mostly, or for cases where you truly will use the collection to contain disparate values (a mishmash of say, JLabels, Strings and Icons for instance for rendering a JTable for instance).
assertEquals("Expected different size", (Integer) 2, dpq.size());
I don't think this should be a problem. dpq.size() should just return an int regardless off what is stored in the priority queue. It would not be a generic value.
You can create something like
DansPriorityQueue<Double> queue = new DansPriorityQueue<Double>();
for(double d = 0; d < 10; d+=1.0)
queue.add(d);
and that should cause no issues, right?

OO strategy to match a set of tokens to an appropriate method / constructor

This question isn't specifically about performing tokenization with regular expressions, but more so about how an appropriate type of object (or appropriate constructor of an object) can be matched to handle the tokens output from a tokenizer.
To explain a bit more, my objective is to parse a text file containing lines of tokens into appropriate objects that describe the data. My parser is in fact already complete, but at present is a mess of switch...case statements and the focus of my question is how I can refactor this using a nice OO approach.
First, here's an example to illustrate what I'm doing overall. Imagine a text file that contains many entries like the following two:
cat 50 100 "abc"
dog 40 "foo" "bar" 90
When parsing those two particular lines of the file, I need to create instances of classes Cat and Dog respectively. In reality there are quite a large number of different object types being described, and sometimes different variations of numbers of arguments, with defaults often being assumed if the values aren't there to explicity state them (which means it's usually appropriate to use the builder pattern when creating the objects, or some classes have several constructors).
The initial tokenization of each line is being done using a Tokenizer class I created that uses groups of regular expressions that match each type of possible token (integer, string, and a few other special token types relevant to this application) along with Pattern and Matcher. The end result from this tokenizer class is that, for each line it parses, it provides back a list of Token objects, where each Token has a .type property (specifying integer, string, etc.) along with primitive value properties.
For each line parsed, I have to:
switch...case on the object type (first token);
switch on the number of arguments and choose an appropriate constructor
for that number of arguments;
Check that each token type is appropriate for the types of arguments needed to construct the object;
Log an error if the quantity or combination of argument types aren't appropriate for the type of object being called for.
The parser I have at the moment has a lot of switch/case or if/else all over the place to handle this and although it works, with a fairly large number of object types it's getting a bit unwieldy.
Can someone suggest an alternative, cleaner and more 'OO' way of pattern matching a list of tokens to an appropriate method call?
The answer was in the question; you want a Strategy, basically a Map where the key would be, e.g., "cat" and the value an instance of:
final class CatCreator implements Creator {
final Argument<Integer> length = intArgument("length");
final Argument<Integer> width = intArgument("width");
final Argument<String> name = stringArgument("length");
public List<Argument<?>> arguments() {
return asList(length, width, name);
}
public Cat create(Map<Argument<?>, String> arguments) {
return new Cat(length.get(arguments), width.get(arguments), name.get(arguments));
}
}
Supporting code that you would reuse between your various object types:
abstract class Argument<T> {
abstract T get(Map<Argument<?>, String> arguments);
private Argument() {
}
static Argument<Integer> intArgument(String name) {
return new Argument<Integer>() {
Integer get(Map<Argument<?>, String> arguments) {
return Integer.parseInt(arguments.get(this));
}
});
}
static Argument<String> stringArgument(String name) {
return new Argument<String>() {
String get(Map<Argument<?>, String> arguments) {
return arguments.get(this);
}
});
}
}
I'm sure someone will post a version that needs less code but uses reflection. Choose either but do bear in mind the extra possibilities for programming mistakes making it past compilation with reflection.
I have done something similar, where I have decoupled my parser from code emitter, which I consider anything else but the parsing itself. What I did, is introduce an interface which the parser uses to invoke methods on whenever it believes it has found a statement or a similar program element. In your case these may well be individual lines you have shown in the example in your question. So whenever you have a line parsed you invoke a method on the interface, an implementation of which will take care of the rest. That way you isolate the program generation from parsing, and both can do well on their own (well, at least the parser, as the program generation will implement an interface the parser will use). Some code to illustrate my line of thinking:
interface CodeGenerator
{
void onParseCat(int a, int b, String c); ///As per your line starting with "cat..."
void onParseDog(int a, String b, String c, int d); /// In same manner
}
class Parser
{
final CodeGenerator cg;
Parser(CodeGenerator cg)
{
this.cg = cg;
}
void parseCat() /// When you already know that the sequence of tokens matches a "cat" line
{
/// ...
cg.onParseCat(/* variable values you have obtained during parsing/tokenizing */);
}
}
This gives you several advantages, one of which being that you do not need a complicated switch logic as you have determined type of statement/expression/element already and invoke the correct method. You can even use something like onParse in CodeGenerator interface, relying on Java method overriding if you want to always use same method. Remember also that you can query methods at runtime with Java, which can aid you further in removing switch logic.
getClass().getMethod("onParse", Integer.class, Integer.class, String.class).invoke(this, catStmt, a, b, c);
Just make note that the above uses Integer class instead of the primitive type int, and that your methods must override based on parameter type and count - if you have two distinct statements using same parameter sequence, the above may fail because there will be at least two methods with the same signature. This is of course a limitation of method overriding in Java (and many other languages).
In any case, you have several methods to achieve what you want. The key to avoid switch is to implement some form of virtual method call, rely on built-in virtual method call facility, or invoke particular methods for particular program element types using static binding.
Of course, you will need at least one switch statement where you determine which method to actually call based on what string your line starts with. It's either that or introducing a Map<String,Method> which gives you a runtime switch facility, where the map will map a string to a proper method you can call invoke (part of Java) on. I prefer to keep switch where there is not substantial amount of cases, and reserve Java Maps for more complicated run-time scenarios.
But since you talk about "fairly large amount of object types", may I suggest you introduce a runtime map and use the Map class indeed. It depends on how complicated your language is, and whether the string that starts your line is a keyword, or a string in a far larger set.

Java use generics to set the primitive type of an array later

I am trying to write some simple numerical code in Java where one can choose between a float and double later. A simplified version of my class looks like the example below:
public class UniformGrid<T> {
public T[] data;
public UniformGrid(int arrayDim) {
data = new T[arrayDim];
}
}
This didn't work I got a generic array creation error when trying to compile. Googling and reading some SO answers I learned about java.lang.reflect.Array and tried to use
data = (T[]) Array.newInstance(T.class, arrayDim);
Which also didn't work, since T is (probably) a primitive type. My Java knowledge is quite rusty (especially when it comes to generics) and I would like to know why the new operator cannot be used with a generic array type. Also of course I am interested in how one would solve this problem in Java.
You cannot create a generic array in Java because of type erasure. The easiest way to get around this would be to use a a List<T>. But if you must use an array, you can use an Object[] for your array and ensure that only T objects are put into it. (This is the strategy ArrayList takes.)
Ex:
private Object[] data = new Object[10];
private int size = 0;
public void add(T obj) {
data[size++] = obj;
}
public T get(int i){
return (T) data[i];
}
Of course you'll get an unchecked warning from your compiler, but you can suppress that.
Generics can't be used when creating an array because you don't know at runtime what type T is. This is called type erasure.
The solution is simple: use List<T> data.
Sorry, you'll have to take another approach:
Type parameters must be reference types, they can't be primitive types.
Only reference types support polymorphism, and only for instance methods. Primitive types do not. float and double don't have a common supertype; you can not write an expression like a + b and choose at runtime whether to perform float addition or double addition. And since Java (unlike C++ or C#, which emit new code for each type parameter) uses the same bytecode for all instances of a generic type, you'd need polymorphism to use a different operator implementation.
If you really need this, I'd look into code generation, perhaps as part of an automated build. (A simple search & replace on the source ought to be able to turn a library operating on double into a library operating on float.)
This is possible, as long as you use Float and Double instead of float and double, as primitive types are not allowed in Java Generics. Of course, this will probably be quite slow. And, you won't be able to (safely) allow direct public access to the array. So this answer is not very useful, but it might be theoretically interesting. Anyway, how to construct the array ...
data = (T[]) new Object[arrayDim];
This will give you a warning, but it's not directly anything to worry about. It works in this particular form - it's inside a generic constructor and data is the only reference to this newly constructed object. See this page about this.
You will not be able to access this array object publicly in the way you might like. You'll need to set up methods in UniformGrid<T> to get and set objects. This way, the compiler will ensure type-safety and the runtime won't give you any problems.
private T[] data;
public void set(int pos, T t) {
data[pos] = t;
}
public T get(int pos) {
return data[pos];
}
In this case, the interface to set will (at compile-time) enforce the correct type is passed. The underlying array is of type Object[] but that's OK as it can take any reference type - and all generic types are effectively List<Object> or something like that at runtime anyway.
The interesting bit is the getter. The compiler 'knows' that the type of data is T[] and hence the getter will compile cleanly and promises to return a T. So as long as you keep the data private and only access it through get and set then everything will be fine.
Some example code is on ideone.
public static void main(String[] args) {
UniformGrid<A> uf = new UniformGrid<A>(1);
//uf.insert(0, new Object()); // compile error
uf.insert(0, new A());
uf.insert(0, new B());
Object o1= uf.get(0);
A o2= uf.get(0);
// B o2= uf.get(0); // compiler error
System.out.println(o1);
System.out.println(o2);
System.out.println("OK so far");
// A via_array1 = uf.data[0]; // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LA;
}
As you would desire, there are compilation errors with uf.insert(0, new Object()) and B o2= uf.get(0);
But you shouldn't make the data member public. If you did, you could write and compile A via_array1 = uf.data[0];. That line looks like it should be OK, but you get a runtime exception: Ljava.lang.Object; cannot be cast to [LA;.
In short, the get and set interface provide a safe interface. But if you go to this much trouble to use an array, you should just use an ArrayList<T> instead. Moral of the story: in any language (Java or C++), with generics or without generics, just say no to arrays. :-)
Item 25 in Effective Java, 2nd Edition talks about this problem:
Arrays are covariant and reified; generics are invariant and erased.
As a consequence, arrays provide run-time type safety but not compile-time type safety and vice versa for generics. Generally speaking arrays and generics don't mix well.

Calling closest fitting method

As part of developing a small ScriptEngine, I reflectively call java methods. A call by the script engine gives me the object the method name and an array of arguments. To call the method I tried to resolve it with a call to Class.getMethod(name, argument types).
This however only works when the classes of the arguments and the classes expected by the Method are the same.
Object o1 = new Object();
Object out = System.out;
//Works as System.out.println(Object) is defined
Method ms = out.getClass().getMethod("println",o1.getClass());
Object o2 = new Integer(4);
//Does not work as System.out.println(Integer) is not defined
Method mo = out.getClass().getMethod("println",o2.getClass());
I would like to know if there is a "simple" way to get the right method, if possible with the closest fit for the argument types, or if I have to implement this myself.
Closest fit would be:
Object o1 = new Integer(1);
Object o2 = new String("");
getMethod(name, o1.getClass())//println(Object)
getMethod(name, o2.getClass())//println(String)
Update:
To clarify what I need:
The Script Engine is a small project I write in my free time so there are no strikt rules I have to follow. So I thought that selecting methods called from the Engine the same way the java compiler selects methods at compile time only with the dynamic type and not the static type of the Object would work.(with or without autoboxing)
This is what I first hoped that the Class.getMethod() would solve. But the Class.getMethod() requires the exact same Classes as argument types as the Method declares, using a subclass will result in a no such method Exception. This may happen for good reasons, but makes the method useless for me, as I don't know in advance which argument types would fit.
An alternate would be to call Class.getMethods() and iterate through the returned array and try to find a fitting method. This would however be complicated if I don't just want to take the first "good" method which I come across, so I hoped that there would be an existing solution which at least handles:
closest fit: If arg.getClass() ==
subclass and methods m(Superclass),
m(Subclass) then call m(Subclass)
variable arguments:
System.out.printf(String ,String...)
Support for autoboxing would be nice, too.
If a call cannot be resolved it may throw an exception ( ma(String,Object), ma(Object, String), args= String,String)
(If you made it till here, thanks for taking the time to read it:-))
As others have pointed out there is no standard method that does this, so you are going to have to implement your own overload resolution algorithm.
It would probably make sense to follow javac's overload resolution rules as closely as possible:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#292575
You can probably ignore generics for a dynamically-typed scripting language, but you might still benefit from the bridge methods that the compiler generates automatically.
Some pitfalls to watch out for:
Class.isAssignableFrom does not know about automatic widening primitive conversions, because these are syntactic sugar implemented in the compiler; They do not occur in the VM or class hierarchy. e.g. int.class.isAssignableFrom(short.class) returns false.
Similarly Class.isAssignableFrom does not know about auto-boxing. Integer.class.isAssignableFrom(int.class) returns false.
Class.isInstance and Class.cast take an Object as an argument; You cannot pass primitive values to them. They also return an Object, so they cannot be used for unboxing ((int) new Integer(42) is legal in Java source but int.class.cast(new Integer(42)) throws an exception.)
I would suggest that you use getMethods(). It returns an array of all public methods (Method[]).
The most important thing here is:
"If the class declares multiple public member methods with the same parameter types, they are all included in the returned array."
What you will then need to do is to use the results in this array to determine which one of them (if any) are the closest match. Since what the closest match should be depends very much on your requirements and specific application, it does make sense to code it yourself.
Sample code illustrating one approach of how you might go about doing this:
public Method getMethod(String methodName, Class<?> clasz)
{
try
{
Method[] methods = clasz.getMethods();
for (Method method : methods)
{
if (methodName.equals(method.getName()))
{
Class<?>[] params = method.getParameterTypes();
if (params.length == 1)
{
Class<?> param = params[0];
if ((param == int.class) || (param == float.class) || (param == float.class))
{
//method.invoke(object, value);
return method;
}
else if (param.isAssignableFrom(Number.class))
{
return method;
}
//else if (...)
//{
// ...
//}
}
}
}
}
catch (Exception e)
{
//some handling
}
return null;
}
In this example, the getMethod(String, Class<?>) method will return a method that with only one parameter which is an int, float, double, or a superclass of Number.
This is a rudimentary implementation - It returns the first method that fits the bill. You would need to extend it to create a list of all methods that match, and then sort them according to some sort of criteria, and return the best matching method.
You can then take it even further by creating the more general getMethod(String, Class<?>) method, to handle more of the possible "close match" scenarios, and possibly even more than one paramter
HTH
Edit: As #finnw has pointed out, be careful when using Class#isAssignableFrom(Class<?> cls), due to its limitations, as I have in my sample code, testing the primitives separately from the Number objects.
AFAIK, there is no simple way to do this kind of thing. Certainly, there's nothing in the standard Java class libraries to do this.
The problem is that there is no single "right" answer. You need to consider all of your use-cases, decide what the "right method" should be and implement your reflection code accordingly.

Categories

Resources