Java generics and streams - java

I'm building a sort of framework to avoid repetition of code, and at a certain point I need to convert a list of object Foo into a list of object Bar.
I have database entities that extend
public class BaseEntity {...}
And presentation objects that extend
public class BaseDTO<T extends BaseEntity> {...}
so
public class Foo extends BaseEntity {...}
and
public class Bar extends BaseDTO<A extends BaseEntity> {
public Bar(Foo entity, Locale l) {
...
}
}
Now to convert a list of Foo into a list of Bar is easy using streams
public abstract ClassThatUsesFooAndBar() {
public List<Bar> convertFooToBar(List<Foo> list) {
return list.stream().map(f -> new Bar(f, locale)).collect(...);
}
}
But, and here is the question, these Foo and Bar are actually generics (A and B), so the class that uses Foo and Bar actually is ClassThatUsesAandB<A extends BaseEntity, B extends BaseDTO>, so that function must be abstract too and implemented as boilerplate code with the correct A and B implementations because obviously you cannot instantiate generic types.
Is there a way to use generics/streams/lambdas to create a function that can be written once, so that the implementing classes don't need to re-implement it? The function signature would be
public List<B> convertAToB(List<A> list);
I hope I've been clear enough in what I need, if you need further explanations please ask
Thank you!

I think the simplest way is to use lambdas for the conversion.
public static <A,B> List<B> convertList(List<A> list, Function<A,B> itemConverter) {
return list.stream().map(f -> itemConverter.apply(f)).collect(...);
}
And then you can use it like this:
List<Bar> l = convertList(fooList,foo -> new Bar(foo.getBaz()));
Or if you want to, you can extract it in its own named class:
public class Foo2BarConverter implements Function<Foo,Bar> {
#Override
public Bar apply(Foo f) {
return new Bar(f.getBaz());
}
}
As an aside, given what we can do with streaming, it seems like a bit of a waste to create a new list just to have a materialised list of Bar objects. I would probably chain whatever operation I want to do with the list straight after the conversion.

The most difficult problem with your question is actually not the boilerplate or the streams, it's the generics. Trying to do new B is a bit of a mess. You can't do it directly, and any workaround isn't too clean.
For the boilerplate, however, you can do a bit better thanks to Java 8's default methods in interface. Consider the following interface:
public interface ConversionHandler<A,B> {
B constructB(A a, Locale locale);
default List<B> convertAToB(List<A> list, Locale locale) {
return list.stream().map(a -> constructB(a, locale)).collect(Collectors.toCollection(ArrayList::new));
}
}
The list conversion boilerplate is now done, all you have to do is implement the B construction in the subclass. However, this is still tricky if B is still generic.
public class ClassThatUsesAandB<A, B> implements ConversionHandler<A,B> {
#Override
public B constructB(A a, Locale locale) {
return null; //This is tricky
}
}
However, if the subclass is concrete, it's quite simple
public class ConverterClass implements ConversionHandler<String,Integer> {
#Override
public Integer constructB(String s, Locale locale) {
return s.length();
}
}
So the followup you may want to search for is a good design pattern for making the construction of generic objects as maintainable and readable as possible.

Related

Enforcing that an object has specific kinds of methods?

I am making a new class that accepts a list of objects as an argument.
However I want to make it so these objects can be anything as long as they have certain methods, for example a .getValue() method that returns a single double, or a .getTimestamp() method that returns a single long, etc.
Can this be done?
You can use an interface or implementation inheritance,
interface Foo{
long getTimestamp();
}
class Bar implements Foo{
... impl ..
}
And then your methods will take a List of subtypes of Foo ( the super type)
void fn(List<? extends Foo> foos){
for(Foo foo:foos){
long time = foo.getTimestamp();
}
}
You can do this by using an interface, as long as you're defining these objects:
interface MyInterface {
double getValue();
long getTimestamp();
}
class MyClass1 implements MyInterface {
#Override
public double getValue() {
// ...
}
#Override
public long getTimestamp() {
// ...
}
}
void someMethod(List<MyInterface> items) {
for (MyInterface item : items) {
double value = item.getValue();
long timestamp = item.getTimestamp();
// ...
}
}
If you're not defining the class of these objects, there's no way to enforce it at compile time. Enforcing it at runtime could be possible with elaborate and ugly reflection hacks.
Interfaces can help you regarding your question. You can have separate implementation for each of the following declaration you provide in it.
Cheers. :)
I think you want reflection. You have no control over the kind of objects that may be passed to your code, you just want to be able to check if they comply to your standards. Right? And when they do, you want to be able to call the expected methods.
Search for "Java reflection".

Generic interface to avoid casting

I want to have an interface that returns different type of interfaces based on what is requested. To explain the issue I used a car example.
public interface ICar{
public ? getCar(String carName);
}
public class Car implements ICar{
public ? getCar(String name){
// Depending on the car name return ICommonCar or IBMW or IAudi...
return new BMW();
Or return new Audi();
...
}
And different users classes will get the ICar interface where they can invoke getCar(carName). Eg.
First class can request:
IBMW mycar = ICar.getCar(BMW);
Second class requests:
IAudi myCar = ICar.getCar(Audi);
I was thinking to use Java Generics to solve the issue but I think there is something that I am missing. My first approach was to something like below:
public class Car<T>{
public T getCar(String carName){
public T newCar;
if(carName.equals(BMW)){
T = new BMW(); // Shall I cast it T?
}else if(carName.equals(Audi))
T = new Audi();
}...
return T;
}
The code above in using Generics doesn't compile but I just put it to show the intention that I want to achieve. The problem seems simple but I found using Generics to be tricky. Is it possible to solve the above problem using Generics? Thank you in advance!
EDIT:
Please consider that in the example I did not meant to imply that IBMW & IAudi as child interfaces of the ICar interface but rather I was thinking to have the ICar as an entry point where different types of checks will be performed on the request & on the class initiating request. Then implementation of unrelated interfaces like IBMW & IAudi which are child interfaces of ICommonCar would be returned. I should have used a different example.
In order to achieve something like you describe, you are going to make the client do as much work as he would do by performing his own cast. I'm changing your class names to make more sense. To whit:
ICarFactory cf = new CarFactory();
// normal way
IAudi audi = ( IAudi )cf.getCar( "audi" );
// your way
IBMW bmw = cf.getCar( "bmw", IBMW.class );
The difference being that in the former case, you need only return ICar from getCar, whereas in the latter, you need to make the method getCar generic in a variable < T extends ICar > and then cast to T before returning your car. That may not even be legal in all cases.
Meantime you get zero help from the compiler regarding types in either case.
It looks like you are looking for a factory pattern. I try to avoid using strings to specify what I want the factory to make - enums are a good fit.
interface Car {
}
class BMW implements Car {
}
class Audi implements Car {
}
interface MakesCars {
Car makeCar() throws InstantiationException, IllegalAccessException;
}
enum Cars implements MakesCars {
BMW(BMW.class),
Audi(Audi.class);
Class<? extends Car> c;
Cars(Class<? extends Car> c) {
}
#Override
public Car makeCar() throws InstantiationException, IllegalAccessException {
return c.newInstance();
}
}
public void test() throws InstantiationException, IllegalAccessException {
Car bmw = Cars.BMW.makeCar();
}
The Java 8 version of the enum is a little more elegant.
enum Cars implements MakesCars {
BMW(BMW::new),
Audi(Audi::new);
final Supplier<Car> supplier;
Cars(Supplier<Car> supplier) {
this.supplier = supplier;
}
#Override
public Car makeCar() {
return supplier.get();
}
}

Simulating function templates in Java

I'm trying to simulate something analogous to a function template in Java, in the sense that I have something like the following:
public interface MyFunctionTemplate<T> {
void doSomething(T thing);
}
public class MyIntegerFunctionTemplate extends MyFunctionTemplate<Integer> { ... }
public class MyStringFunctionTemplate extends MyFunctionTemplate<String> { ... }
It appears that I will need a central registry of some sort. Something like the following:
public class MyFunctionTemplateRegistry {
private static Map<Class<?>, MyFunctionTemplate<?>> registry;
public static <T> void register(Class<T> templateClass, MyFunctionTemplate<T> templateFunction);
public static void doSomething(Object thing);
}
What is the best way to design such a thing?
Well, it depends on what you want to achieve and whether the implementing class needs to know the type or not. To me, your suggestion seems overdesigned (too complex), but it is really hard to say without having more concrete information.
The reason I'm saying this, is that I don't like the fact that you want to implement two separate classes for your interface (one for each type). The strength of using generics is often in finding a way to implement it with one class using the generic type T.
Then again, I might have misunderstood your intentions here...
Anyway, as a simple example, if your function(s) are purely mathematical, something like getMax() and getMin(), then you surely don't need to know anything more about T than the fact that T is comparable with T.
Then you could end up with something like this:
public class FindExtremes<T extends Comparable<T>> {
T getMax(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
T getMin(T a, T b) {
return a.compareTo(b) <= 0 ? a : b;
}
}
This could the be used directly for any class that implements Comparable, e.g.
new FindExtremes<Integer>().getMax(4, 5);
new FindExtremes<Double>().getMax(4.444D, 5.555D);
new FindExtremes<String>().getMax("abc", "zyx");

Enforcing return type for an class that implements an interface

How do I enforce that the method getFoo() in the implementing class, returns a list of the type of same implementing class.
public interface Bar{
....
List<? extends Bar> getFoo();
}
Right now a class that implements Bar returns objects of any class that implements Bar. I want to make it stricter so that the class that implements Bar returns a List of objects of only its type in getFoo().
Unfortunately this cannot be enforced by Java's type system.
You can get pretty close, though, by using:
public interface Bar<T extends Bar<T>> {
List<T> getFoo();
}
And then your implementing classes can implement it like so:
public class SomeSpecificBar implements Bar<SomeSpecificBar> {
// Compiler will enforce the type here
#Override
public List<SomeSpecificBar> getFoo() {
// ...
}
}
But nothing stops another class from doing this:
public class EvilBar implements Bar<SomeSpecificBar> {
// The compiler's perfectly OK with this
#Override
public List<SomeSpecificBar> getFoo() {
// ...
}
}
This is not possible in Java, but you might wonder what the use-case is to force this in the interface.
If you program against the interface (which you typically do, why else define the interface) the type wouldn't be known
If you program against a specific class, this thread already provided options on how you can implement that specific class to return a List<itself>. And since you program against that specific class, the compiler has access to that specific return type and knows about it
The interface Bar<T extends Bar<T>> answers already here are right, but I just wanted to add that if this is really something you want to enforce, you may want to look at composing your objects rather than using inheritance. Without knowing too much about your classes, it might look something like this:
public interface FooGetter<T> {
List<? extends T> getFoo();
}
public class FooComposer<T extends Bar> {
...
final T bar;
final FooGetter<T> barGetter;
}
Or it could look very different... but the main point is that if you want the two Ts to match, composition may be the answer.
Of course, even that can be circumvented using raw types... but then again, if someone does that, they're just using a raw List, and when they get ClassCastExceptions you can safely hit them. :)
You should infer the generic on Bar:
public interface Bar<T extends Foo> {
...
List<T> getFoo();
}
You can just parameterize the method, but that will not ensure that the return type matches that of the class.
Maybe sth like this
public interface Bar {
....
List<? extends Bar> getFoo();
}
public class T implements Bar {
List<T> getFoo();
}
public class TestClass extends T {};
I liked yshavit answer best but I could not understand the code.
So I will try to write the code as I think it should be.
interface Bar
{
// stuff
// don't bother with the getFoo method
}
interface BarUtils
{
< T extends Bar > List < ? extends T > getFoo ( T bar ) ;
}
How about this:
interface Bar
{
// everything but getFoo ( ) ;
}
interface FooGetter < T >
{
List < ? extends T > getFoo ( ) ;
}
interface BarRef < T extends Bar & FooGetter < T > >
{
T get ( ) ;
}
anything that implements BarRef must implement T and anything that implements T must have the appropriately enforced getFoo method.

Is there a way to say "method returns this" in Java?

Is there a way to say "this method returns this" using Generics?
Of course, I want to override this method in subclasses, so the declaration should work well with #Override.
Here is an example:
class Base {
public Base copyTo (Base dest) {
... copy all fields to dest ...
return this;
}
}
class X extends Base {
#Override
public X copyTo (X dest) {
super.copyTo (dest);
... copy all fields to dest ...
return this;
}
}
public <T extends Base> T copyTo (Base dest) doesn't work at all: I get "Type mismatch: Can't convert from Base to T". If I force it with a cast, the override fails.
You can do something very clever (and akin to what they have done in Scala with the 2.8 collection framework). Declare some interface method that should return "itself" (Note: This is a type parameter, not a keyword!)
public interface Addable<T, This extends Addable<T, This>> {
public This add(T t);
}
Now declare a level of indirection - a "template" class
public interface ListTemplate<A, This extends ListTemplate<A, This>>
extends Addable<A, This>{
}
public interface List<A> extends ListTemplate<A, List<A>> {
}
Then an implementation of List has to return a List from the add method (I'll let you fill in the impl details)
public class ListImpl<A> implements List<A> {
public List<A> add(A a) {
return ...
}
}
Similarly you could have declard a SetTemplate and a Set to extend the Addable interface - the add method of which would have returned a Set. Cool, huh?
No, there's no way of expressing that. Just declare the method to return the type of the class. Java has covariant return types, so you can override a method to return a more specific type anyway.
If you wanted to have some marker for this, you could always introduce your own annotation - but don't expect any other tools to take any particular notice of it.
EDIT: the answer from oxbow_lakes does indeed give something which will work in most cases, but I believe there are ways of fooling it such that you're actually dealing with a different type. (From memories of experimentation, anyway.) Note that this is similar to how Java enums work.
using covariant types should be simple as:
abstract class Foo<T> {
Foo<T> get() {
return this.getClass().cast(this);
}
}
class Bar extends Foo {
#Override
Bar get() {
return (Bar) super.get();
}
}

Categories

Resources