I have the following Code which is a boiled-down version of something I've stumbled upon:
public class Transforming
{
static interface MyInterface<T>
{
void consume(T... toConsume);
}
static abstract class Mapper<T> implements MyInterface<String> {
MyInterface<T> delegate;
public Mapper(MyInterface<T> delegateTo)
{
delegate = delegateTo;
}
public void consume(String... transformFrom)
{
T[] array = (T[]) Arrays.stream(transformFrom)
.map(this::transform)
.toArray(); // can't toArray(T[]::new) here!
delegate.consume(array);
}
protected abstract T transform(String toTransform);
}
}
The searches on how to transform streams to arrays fall short obviously since I don't have the resulting type of array at this point, and Java doesn't allow me to create arrays of a generic type...
I do understand the issue, but any input on how to clean code this?
AFAICT, my options here are
change the interface from varargs to List
the cast I'm using in the code sample
adding an IntFunction to the Mapper creation
Anything I'm missing?
What would be your preference?
The way I handle this is by always providing two overloads:
One which accepts varargs
One which accepts a List<>.
The varargs overload never does anything other than pack the array into a list and invoke the List<> overload. This keeps things simple. No-brainer.
So, essentially, the option I'd choose is your first option, "change the interface from varargs to List", except that you do not actually have to change it, you can just extend it by adding an overload.
Your abstract Mapper class could use an abstract toArray method which provide the typed conversion from list to array.
static abstract class Mapper<T> implements MyInterface<String> {
#Override
public void consume(String... transformFrom) {
T[] array = toArray(Arrays.stream(transformFrom)
.map(this::transform)
.collect(Collectors.toList()));
delegate.consume(array);
}
protected abstract T transform(String toTransform);
protected abstract T[] toArray(List<T> list);
}
In implementations just implement a basic list.toArray(..) method
public static void main(String[] args) {
Mapper myMap = new Mapper<Integer>(new MapperInt()) {
#Override
protected Integer transform(String toTransform) {
return new Integer(toTransform);
}
#Override
protected Integer[] toArray(List<Integer> list) {
return list.toArray(new Integer[list.size()]);
}
};
myMap.consume("1","2");
}
public static class MapperInt implements MyInterface<Integer> {
#Override
public void consume(Integer... toConsume) {
for(Integer i: toConsume)
System.err.println(i);
}
}
Related
I have the following interface with generic and an implentation class:
public interface DataInterface<T> {
T getData();
void printData();
}
public class IntegerData implements DataInterface<Integer> {
private Integer value;
public IntegerData(Integer value) {
this.value = value;
}
#Override
public Integer getData() {
return null;
}
#Override
public void printData() {
System.out.println(this.value);
}
}
And here my code that use the class:
public class Main {
public static void main(String[] args) {
List<IntegerData> dataList = new ArrayList<>();
dataList.add(new IntegerData(1));
doSomething(dataList); <-- Compiler error
//this work
doSomething(Collections.unmodifiableList(dataList));
doSomething(new ArrayList<>(dataList));
}
private static void doSomething(List<DataInterface<?>> dataList) {
for (DataInterface<?> data : dataList)
data.printData();
}
}
If I try to call the doSomething method with the List type, the compiler complains with "The method doSomething(List<DataInterface<?>>) in the type Main is not applicable for the arguments (List)".
But if I wrap my specific list or create a new one, then it works. I wonder why the direct call doesn't work. What is the reason?
A List<IntegerData> or List<DataInterface<Integer>> is not compatible with List<DataInterface<?>>, because I can also add a DataInterface<String> to the latter. The solution is to use extends:
private static void doSomething(List<? extends DataInterface<?>> dataList)
This will prevent adding anything to the list (except null), and is therefore safe to use.
By wrapping the list, the generic type is changed due to type inference. If you'd assign it to a variable using var it would also fail.
This code displays what I want to do (but does not work).
abstract class Item<I extends Item<I>> {
public abstract void add();
public abstract void test();
public static <T extends Item<T>> Item<T> getZero() {
return T.ZERO();
}
protected static <T extends Item<T>> Item<T> ZERO() {
class ZERO extends Item<T> {
public void add() {}
public void test() { System.out.println("item"); } // don't call this
}
return new ZERO();
}
public static void main(String[] args) {
Item.<Book>getZero().test();
}
}
class Book extends Item<Book> {
public void add() { /* addition implementation goes here */ }
public void test() { System.out.println("book"); } // this should be called
protected static Item<Book> ZERO() { return new Book(); }
}
I want to make sure that when Item.<Book>getZero(), it calls Book.ZERO() instead of Item.ZERO(). However, due to type erasure, this does not work, and the program prints item.
I want to modify this to make this work (preferably avoiding the use of reflection). Here is the purpose of this:
If I call Arrays.stream(books).collect(Item.<Book>getZero(), Item::add, Item::add);, I want to be able to add all of the items.
To facilitate computation (and avoid dealing with Optional<Book>), I want to define a concrete ZERO object. However, since I intend all implementations of Item to be mutable, I want to make sure that each subclass of Item (such as book) has its own mutable implementation. In other words, the default implementation of ZERO is a placeholder for operations and should not be used.
I want to do this without passing extra objects to the calling methods (addition / zero methods should be inherent in each implementation of Item) and without requiring an instance of an Item object to create a ZERO object. This is useful to me because I want to perform operations with Items knowing only that they can be added and compared, which allows me to save the implementation of Item for later.
Assuming that the items you want to collect have the same type (this cannot be checked statically), you can make the instance method (not static method) returning zero and defer the container creation until the first element is collected. Something like this:
abstract class Item<I extends Item<I>> {
public abstract void add(I another);
public abstract void test();
// Instance method: returns new ZERO-container of the same type like this object
// Actually could be abstract
public I getZero() {
class ZERO extends Item<I> {
#Override
public void add(I another) {}
#Override
public void test() { System.out.println("item"); } // don't call this
}
return (I) new ZERO();
}
// Creates collector which aggregates any specific type of items
public static <T extends Item<T>> Collector<T, ?, T> collector() {
class Container {
T acc;
}
return Collector.of(Container::new, (cont, t) -> {
// accumulator is initialized only on first addition
// so we can use the first element to request the ZERO of the same type
if(cont.acc == null) cont.acc = t.getZero();
cont.acc.add(t);
}, (c1, c2) -> {
if(c1.acc == null) return c2;
if(c2.acc != null) c1.acc.add(c2.acc);
return c1;
}, cont -> cont.acc); // unpack in finisher (returns null for empty stream)
}
}
Now we can redefine methods in subclasses:
class Book extends Item<Book> {
public void add(Book another) { System.out.println("Book added"); }
public void test() { System.out.println("book"); }
public Book getZero() { return new Book(); }
}
class Food extends Item<Food> {
public void add(Food another) { System.out.println("Food added"); }
public void test() { System.out.println("food"); }
public Food getZero() { return new Food(); }
}
And you can use the same collector regardless of the actual types of collected objects:
Book books = Stream.of(new Book(), new Book()).collect(Item.collector());
Food foods = Stream.of(new Food(), new Food()).collect(Item.collector());
Note that for empty input stream you will have null returned as you have no objects to mimic ZERO from. If this is unacceptable, then the only solution I could propose is to pass around Class<? extends Item> object and create the corresponding ZERO using reflection (like clazz.getMethod("getZero").invoke(null) assuming getZero is static).
When you say you want to be able to write
Arrays.stream(books).collect(Item.<Book>getZero(), Item::add, Item::add);
you seem to be unaware that due to type erasure, the method Item.getZero() has no knowledge about the type parameter <Book> you have specified. The behavior of a method does not change due to its parametrization. In fact, you can even write Item.<Book>getZero() when the Item.getZero() method is not generic at all.
But what’s even more important, your desire to have code that is independent of the actual type is not fulfilled at all. In the term Item.<Book>getZero() there is a reference to the type Book which has to be adapted when the stream element type is a different subtype of Item. So why not specify Book::ZERO (or just Book::new) in the first place?
abstract class Item<I extends Item<I>> {
public abstract void add(I other);
public abstract void test();
}
class Book extends Item<Book> {
public void add(Book b) { /* addition implementation goes here */ }
public void test() { System.out.println("book"); } // this should be called
public static Book ZERO() { return new Book(); }
}
Usable as
Book b = Arrays.stream(books).collect(Book::ZERO, Item::add, Item::add);
so before complicating the design, you should think about what you actually can gain from the change.
Note that the Supplier needed as first argument to collect is exactly the abstraction of a method that returns a specific object (like the zero instance) that you are looking for. When extracting the supplier from the collect operation, you can abstract the operation, e.g. when you add the following method to the Item class
static <T extends Item<T>> Collector<T,T,T> sum(Supplier<T> getZero) {
return Collector.of(getZero, Item::add, (a,b)->{ a.add(b); return a; });
}
you can use it like
Book b = Arrays.stream(books).collect(Item.sum(Book::ZERO));
I have a class AbstractExtractionRules which constructor receives a ParserAPI object. The AbstractExtractionRules will be implemented using many different Parser APIs and each uses its own abstraction of 'Document'.
ParserAPI class has a parameterized type that represents the return type for the method parseDocument.
I want a way to use the ParserAPI in AbstractExtractionRules subclasses without the need of cast, leaving it in a more natural way.
I think with java generics, perhaps modifying the constructor parameter accordingly or modifying the call for getParserAPI().parseDocument(htmlCode) I can reach this, but I do not know how to do.
#FunctionalInterface
public interface ExtractionRules<T> {
List<T> extract(String htmlCode);
}
public interface ParserAPI<T> {
T parseDocument(String htmlCode);
}
public abstract class AbstractExtractionRules <T> implements ExtractionRules <T> {
private ParserAPI<?> parserAPI;
public AbstractExtractionRules(ParserAPI<?> parserAPI) {
this.parserAPI = parserAPI;
}
public ParserAPI<?> getParserAPI() {
return parserAPI;
}
}
public class RibeiraoVisitorRule extends AbstractExtractionRules <String> {
public RibeiraoVisitorRule(ParserAPI<Document> parserAPI) {
super(parserAPI);
}
#Override
public List extract(String htmlCode) {
List<String> list = new ArrayList<>();
Document doc = (Document) getParserAPI().parseDocument(htmlCode);
Elements submenu = doc.select("a.new_sub_menu");
submenu.forEach(element1 -> {
String href = element1.attr("abs:href");
list.add(href.concat("&pageNum=VER-TUDO"));
});
return list;
}
}
You can pass type from AbstractExtractionRules to ParserAPI:
public abstract class AbstractExtractionRules<A, T> implements ExtractionRules<T> {
private ParserAPI<A> parserAPI;
Then you can call it without cast in concrete implementation class:
public class RibeiraoVisitorRule extends AbstractExtractionRules<Document, String> {
#Override
public List<String> extract(String htmlCode) {
...
Document doc = getParserAPI().parseDocument("");
}
Note that I also added passing type T to ExtractionRules interface. It affects the return type of extract() method. In your example you did not pass the type so return type of the method was List.
This question already has answers here:
Return Type of Java Generic Methods
(5 answers)
Closed 6 years ago.
I am reading generics and tried writing the below code. There are no compilation error.
import java.util.*;
public class JavaApplication14 {
public<T> void run (T obj ) {
//Do Something
}
public static void main(String[] args) {
JavaApplication14 m= new JavaApplication14();
m.run(new ArrayList<>());
m.run(new Interger(5);
m.run(5);
}
}
If the function is
public<T extends Number> void run (T obj) {
//Do Something
}
It makes sense as we can restrict the arguments of this function to a Number and its subtypes. But am terribly confused what the function 'run' without any bound mean?
Can it now take any object as the argument ? In what scenario do i need to use such a function with generics ?
Part of your confusion may stem from the fact that there is no point in having run be a generic method in this case. You normally use a type parameter to create a relationship between two parameter types and/or between parameter type and return type. In your example run could just as well have been declared as requiring an Object parameter (a type parameter without a declared bound effectively has Object as its bound).
There is one case I know of where you might usefully use a type parameter in a single parameter type: when you want to be able to manipulate a collection in a way that doesn't depend on the element type, but which does require inserting elements into the collection. Consider for example a hypothetical "reverse list" method:
<T> void reverse(List<T> list)
{
List<T> reversed = new ArrayList<T>();
for (int i = list.size(); i > 0; i--) {
reversed.add(list.get(i - 1));
}
list.clear();
list.addAll(reversed);
}
It would be difficult to write this in a way that didn't require a type parameter, i.e. that takes a List<?> parameter. The only way to do it without casts is to do:
void reverse2(List<?> list)
{
reverse(list); // call reverse as defined above!
}
But again, this doesn't apply in the example you discuss.
So in summary:
A type parameter without an explicit bound effectively has an Object bound.
There are two reasons why a method might need a type parameter (either with or without an explicit bound):
Specify a relationship between parameter types and/or return type
Capture a potential wildcard as a type parameter to allow operations that wouldn't otherwise be possible (as in the reverse example).
The example method you discussed:
public<T> void run (T obj )
... does neither of these, and so the type parameter is pointless. The method might just as well have been declared as public void run(Object obj).
It allows you to avoid any cast.
public class SomeClass {
void doStuff();
}
public<T extends SomeClass> void run (T obj) {
//can call doStuff without any casting
obj.doStuff();
}
public<T> void run (T) {
//Here, there's no clue to perform the implicit cast.
obj.doStuff(); //won't compile
}
While in this case the function could take Object just as well, the variant that makes sense to you is equivalent to public void run(Number obj) { ... } as well. For an example where lack of bound makes sense consider a case where the return type mentions T: public <T> List<T> singletonList(T obj).
Some theory
There're generic methods. Their main goal is generic algorithms (receive and return same types).
Code that uses generics has many benefits over non-generic code:
Elimination of casts.
Stronger type checks at compile time.
Enabling programmers to implement generic algorithms.
A little practice
Consider the following code:
class MyClass {
public void method() {}
public static void main(String[] args) {
runFirst(new MyClass());
runSecond(new MyClass());
}
public static <T extends MyClass> void runFirst(T obj) {
obj.method();
}
public static <T> void runSecond(T obj) {
((MyClass) obj).method();
}
}
The runFirst() method allows us to avoid cast to class and all its subclasses. In runSecond() method we can get any type of parameter (<T>, roughly speaking, means <T extends Object>). Firstly, we must cast to MyClass and then call its method.
First of all I will start with the meaning of public <T> void run(T object) { ... }. Yes when you use that kind of code you than you may use any object as a parameter of run. If you want to restrict the arguments of this function to a specific interface, class or its sub classes you can just write code like NotGenericRun which is shown below.
public class NotGenericRun {
public void run(ArrayList<?> list) {
String message = "Non Generic Run List: ";
System.out.println(message.concat(list.toString()));
}
public void run(int intValue) {
String message = "Non Generic Run Int: ";
System.out.println(message.concat(String.valueOf(intValue)));
}
}
Here I tested output of GenericRun and NotGenericRun classes.
public class TestClass {
public static void main(String[] args) {
GenericRun m = new GenericRun();
m.run(new ArrayList<>());
m.run(new Integer(5));
m.run(5);
NotGenericRun n = new NotGenericRun();
n.run(new ArrayList<>());
n.run(new Integer(5));
n.run(13);
}
}
Output of this code was following:
Generic Run: []
Generic Run: 5
Generic Run: 5
Non Generic Run List: []
Non Generic Run Int: 5
Non Generic Run Int: 13
When you use Generic run as I already said arguments may be any object but there is other way of restricting the arguments while still using generics.
public class GenericRun {
public <T> void run(T object) {
String message = "Generic Run: ";
System.out.println(message.concat(object.toString()));
}
}
This is how.
public class GenericRun <T> {
public void run(T object) {
String message = "Generic Run: ";
System.out.println(message.concat(object.toString()));
}
}
In this case you'll be using GenericClass like this:
GenericRun<Integer> m = new GenericRun<Integer>();
m.run(new Integer(5));
m.run(5);
and only value that it will be tacking should be stated while creating class. I can't think of scenario when public <T> void run(T object) { ... } may be needed but it might occur when you'll need the method to get every argument or you don't know what arguments will be (but it's really less likely). I think more often when you'll be using generics with run like this:
public class GenericRun <T> {
public void run(T object) {
...
}
}
I was searching about usage of generic methods here you can read more about why may we need generic methods.
Here is another example:
public class GenericRun {
public <T> void run(T[] inputArray) {
for (T element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
Using this class you can print array of different type using a single Generic method:
public class TestClass {
public static void main(String[] args) {
GenericRun m = new GenericRun();
// Create arrays of Integer, Double and Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("Array integerArray contains:");
m.run(intArray); // pass an Integer array
System.out.println("\nArray doubleArray contains:");
m.run(doubleArray); // pass a Double array
System.out.println("\nArray characterArray contains:");
m.run(charArray); // pass a Character array
}
}
I hope I answered your question.
The only thing makes sense here is if this was some kind of pseudo-abstract or base class, that provided framework for behaviour and let another coders implement their own logic, but also provided default null action.
It could allow for better generic type-setting, for example as:
class MySubClass extends JavaApplication14 {
public <T> void run(T obj){
new ArrayList<T>().add(obj);
}
}
I'm having some problems with a method returning a generic list. The code is basically this:
public class MyClass{
private List<MyListElement> myList = new ArrayList<MyListElement>();
public <E> List<E> getGenericList(){
return new ArrayList<E>();
}
public void thisWorks(){
List<MyListElement> newList = getGenericList();
myList.addAll(newList);
}
public void thisDoesntWork(){
myList.addAll(getGenericList());
}
public void thisDoesntWorkEither(){
for(MyListElement elem : getGenericList()){
fiddle();
}
}
}
Why does the thisDoesntWork() method not work, and is there any other way around it (other than doing it the thisWorks() way which isn't always practical)?
The compiler cannot infer what type to choose for the type parameter <E> of the generic method getGenericList() in thisDoesntWork().
In this case you need to explicitly state the Type for the type argument by calling <MyListElement>getGenericList()
Alternatively you can change the signature of getGenericList() to accept a Class<E> argument. Then you would invoke getGenericList(MyListElement.class) in both thisWorks() and thisDoesntWork(). Admittedly that's a bit more verbose, but definitly more intuitive to clients of your method.
I would say as a general rule, try to make the type arguments of your generic methods be inferrable from that method's arguments.
You can change thisDoesntWork() like so:
public void thisDoesntWork(){ // well, it works now
myList.addAll(this.<String>getGenericList());
}
You need to tell the compiler what type getGenericList() is dealing with.
The type argument to the generic method <E> getGenericsList() can be passed at call time:
this.<String>getGenericsList()
otherwise the compiler does its best to deduce it from the context. When you assign the returned object to a List<String> reference, the compiler hence infers that you passed String as the type argument.
Given the List API:
List<E> {
void addAll(Collection<? extends E> c);
}
the compiler doesn't seem to be able to infer the correct type, and to be honest I don't know if this is because it is not smart enough, or because it doesn't want to carry the responsibility by design.
I even made a test to see if the problem is the wildcard, or if addAll() cannot infer the type arguments from the parameterized type, but nothing seems to work:
public class GenericsList {
public static void main(String[] args) {
// same signature as Java API
List<String> base = new List<String>();
base.addAll(GenericsList.getList()); // ERROR!
// addAll() doesn't use a wildcard
List2<String> base2 = new List2<String>();
base2.addAll(getList2()); // ERROR!
// what about a generic method?
addAll(base, getList()); // ERROR!
}
static <E> List<E> getList() {
return new List<E>();
}
static <E> void addAll(List<E> src, List<E> other) {}
static <E> List2<E> getList2() {
return new List2<E>();
}
static class List<E> {
void addAll(List<? extends E> other) {}
}
static class List2<E> {
void addAll(List2<E> other) {}
}
}
This code will work for you.
getGenericList() should know what it is returning and that should be compatible with your list type.
You need not cast it to String or any other as suggested by others as it will restrict your getGenericList method intention by tying it to string type.
public class MyClass{
private List<MyListElement> myList = new ArrayList<MyListElement>();
public <E extends MyListElement> List<E> getGenericList(){
return new ArrayList<E>();
}
public void thisWorks(){
List<MyListElement> newList = getGenericList();
myList.addAll(newList);
}
public void thisDoesntWork(){
myList.addAll(getGenericList());
}
public void thisDoesntWorkEither(){
for(MyListElement elem : getGenericList()){
fiddle();
}
}
}