Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #35482 > unrolled thread

Java 8 Lambda with generic types

Started byStone Zhong <stone.zhong@gmail.com>
First post2016-08-27 23:50 -0700
Last post2016-09-02 15:18 -0700
Articles 14 — 4 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-08-27 23:50 -0700
    Re: Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-08-28 00:02 -0700
      Re: Java 8 Lambda with generic types Arne Vajhøj <arne@vajhoej.dk> - 2016-08-28 07:46 -0400
        Re: Java 8 Lambda with generic types Steven Simpson <ss@my.domain.invalid> - 2016-08-28 15:00 +0100
          Re: Java 8 Lambda with generic types Lew <lewbloch@gmail.com> - 2016-08-30 22:25 -0700
            Re: Java 8 Lambda with generic types Steven Simpson <ss@my.domain.invalid> - 2016-08-31 17:19 +0100
    Re: Java 8 Lambda with generic types Steven Simpson <ss@my.domain.invalid> - 2016-08-28 08:19 +0100
    Re: Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-08-28 03:26 -0700
    Re: Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-08-28 07:45 -0700
      Re: Java 8 Lambda with generic types Arne Vajhøj <arne@vajhoej.dk> - 2016-08-28 13:22 -0400
    Re: Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-08-28 07:57 -0700
    Re: Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-08-28 10:43 -0700
      Re: Java 8 Lambda with generic types Arne Vajhøj <arne@vajhoej.dk> - 2016-08-30 20:35 -0400
    Re: Java 8 Lambda with generic types Stone Zhong <stone.zhong@gmail.com> - 2016-09-02 15:18 -0700

#35482 — Java 8 Lambda with generic types

FromStone Zhong <stone.zhong@gmail.com>
Date2016-08-27 23:50 -0700
SubjectJava 8 Lambda with generic types
Message-ID<df44fc1a-9d48-4ba8-890e-a687d24062a9@googlegroups.com>
Hi there, 

It seems sometimes, the compiler is not smart enough to decide the generic parameter type based on labmda argument types, here is an example:

I have a interface, say Toy:

public interface Toy<E> {
    List<E> get();
}


Now I have a method to process toys, such as:
    public static void checkToy(Toy<?> toy) {
    }

Now, the following code works
        checkToy(new Toy<Integer>() {
            @Override
            public List<Integer> get() {
                List<Integer> ret = Arrays.asList(10);
                return ret;
            }
        });

However, if I have 
        checkToy(() -> {
            return Arrays.<Integer>asList(10);
        });

I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?

Thanks,
Stone

[toc] | [next] | [standalone]


#35483

FromStone Zhong <stone.zhong@gmail.com>
Date2016-08-28 00:02 -0700
Message-ID<cf527430-e940-4ba7-9579-096d1c80bd84@googlegroups.com>
In reply to#35482
On Saturday, August 27, 2016 at 11:50:40 PM UTC-7, Stone Zhong wrote:
> Hi there, 
> 
> It seems sometimes, the compiler is not smart enough to decide the generic parameter type based on labmda argument types, here is an example:
> 
> I have a interface, say Toy:
> 
> public interface Toy<E> {
>     List<E> get();
> }
> 
> 
> Now I have a method to process toys, such as:
>     public static void checkToy(Toy<?> toy) {
>     }
> 
> Now, the following code works
>         checkToy(new Toy<Integer>() {
>             @Override
>             public List<Integer> get() {
>                 List<Integer> ret = Arrays.asList(10);
>                 return ret;
>             }
>         });
> 
> However, if I have 
>         checkToy(() -> {
>             return Arrays.<Integer>asList(10);
>         });
> 
> I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?
> 
> Thanks,
> Stone

I just learned if I put all generic parameter in the method parameter even if you do not use it, it helps the compiler to find the right generic parameter type when instantiate the instance. for example:

public interface Toy<E> {
    List<E> get(E dummy);
}

did kind of solve the problem, but I do feel bit clumsy doing such thing.

[toc] | [prev] | [next] | [standalone]


#35486

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-28 07:46 -0400
Message-ID<npuiub$1a5i$1@gioia.aioe.org>
In reply to#35483
On 8/28/2016 3:02 AM, Stone Zhong wrote:
> On Saturday, August 27, 2016 at 11:50:40 PM UTC-7, Stone Zhong wrote:
>> It seems sometimes, the compiler is not smart enough to decide the
>> generic parameter type based on labmda argument types, here is an example:
>>
>> I have a interface, say Toy:
>>
>> public interface Toy<E> {
>>     List<E> get();
>> }
>>
>>
>> Now I have a method to process toys, such as:
>>     public static void checkToy(Toy<?> toy) {
>>     }
>>
>> Now, the following code works
>>         checkToy(new Toy<Integer>() {
>>             @Override
>>             public List<Integer> get() {
>>                 List<Integer> ret = Arrays.asList(10);
>>                 return ret;
>>             }
>>         });
>>
>> However, if I have
>>         checkToy(() -> {
>>             return Arrays.<Integer>asList(10);
>>         });
>>
>> I got compiling error: "List<Integer> cannot be converted to
>> List<Object>", it seems compiler tried to create a instance of
>> Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait
>> to tell the compiler it is Toy<Integer> explicitly with the lambda
>> expression?
>
> I just learned if I put all generic parameter in the method
> parametereven if you do not use it, it helps the compiler to find the
 > right generic parameter type when instantiate the instance.
 > for example:
>
> public interface Toy<E> {
>     List<E> get(E dummy);
> }
>
> did kind of solve the problem, but I do feel bit clumsy doing such thing.

I think the problem really is in your checkToy method.

The following works fine:

import java.util.Arrays;
import java.util.List;

public class GenFun {
     public static interface Toy<E> {
         public List<E> get();
     }
     public static <E> void checkToy(Toy<E> toy) {
         for(E o : toy.get()) {
             System.out.println(o);
         }
     }
     public static void main(String[] args) {
         checkToy(new Toy<Integer>() {
             @Override
             public List<Integer> get() {
                 List<Integer> ret = Arrays.asList(10);
                 return ret;
             }
         });
         checkToy(() -> { return Arrays.<Integer>asList(10); });
     }
}

Arne

[toc] | [prev] | [next] | [standalone]


#35487

FromSteven Simpson <ss@my.domain.invalid>
Date2016-08-28 15:00 +0100
Message-ID<jd7b9d-imi.ln1@s.simpson148.btinternet.com>
In reply to#35486
On 28/08/16 12:46, Arne Vajhøj wrote:
> I think the problem really is in your checkToy method.
>
> The following works fine:
>
> import java.util.Arrays;
> import java.util.List;
>
> public class GenFun {
>     public static interface Toy<E> {
>         public List<E> get();
>     }
>     public static <E> void checkToy(Toy<E> toy) {

I found that worked too, but what is the difference between that and 
<?>, when E is only referenced once?


-- 
ss at comp dot lancs dot ac dot uk

[toc] | [prev] | [next] | [standalone]


#35509

FromLew <lewbloch@gmail.com>
Date2016-08-30 22:25 -0700
Message-ID<74d17a27-7891-4de2-963d-387108bb6874@googlegroups.com>
In reply to#35487
On Sunday, August 28, 2016 at 7:15:11 AM UTC-7, Steven Simpson wrote:
> On 28/08/16 12:46, Arne Vajhøj wrote:
> > I think the problem really is in your checkToy method.
> >
> > The following works fine:
> >
> > import java.util.Arrays;
> > import java.util.List;
> >
> > public class GenFun {
> >     public static interface Toy<E> {
> >         public List<E> get();
> >     }
> >     public static <E> void checkToy(Toy<E> toy) {
> 
> I found that worked too, but what is the difference between that and 
> <?>, when E is only referenced once?

When you use a wildcard in lieu of the generic type parameter, you are losing the information that the type in the <?> is the same as `E`. There is no way for the compiler to know that the type of the `Toy<?> toy` argument is compatible with `E`. 

The problem is not with lambdas, but with your incorrect generics.

-- 
Lew

[toc] | [prev] | [next] | [standalone]


#35524

FromSteven Simpson <ss@my.domain.invalid>
Date2016-08-31 17:19 +0100
Message-ID<skcj9d-c56.ln1@s.simpson148.btinternet.com>
In reply to#35509
On 31/08/16 06:25, Lew wrote:
> On Sunday, August 28, 2016 at 7:15:11 AM UTC-7, Steven Simpson wrote:
>> On 28/08/16 12:46, Arne Vajhøj wrote:
>>> public class GenFun {
>>>      public static interface Toy<E> {
>>>          public List<E> get();
>>>      }
>>>      public static <E> void checkToy(Toy<E> toy) {
>> I found that worked too, but what is the difference between that and
>> <?>, when E is only referenced once?
> When you use a wildcard in lieu of the generic type parameter, you are losing the information that the type in the <?> is the same as `E`. There is no way for the compiler to know that the type of the `Toy<?> toy` argument is compatible with `E`.

It's possible I've conflated Arne's portion of the discussion with my 
own (my mistake), so I'm not sure which E you're referring to.

I mean, if we have:

   interface Toy<F> { List<F> get(); }

   static <E> void checkToy1(Toy<E> toy) { }
   static void checkToy2(Toy<?> toy) { }

   static List<Integer> makeList() { ... }

...why does the compiler accept checkToy1(() -> makeList()), but not 
checkToy2(() -> makeList())?

Is there a simpler case to demonstrate the distinction?  Is there one 
without lambdas/method references?

-- 
ss at comp dot lancs dot ac dot uk

[toc] | [prev] | [next] | [standalone]


#35484

FromSteven Simpson <ss@my.domain.invalid>
Date2016-08-28 08:19 +0100
Message-ID<usfa9d-k75.ln1@s.simpson148.btinternet.com>
In reply to#35482
On 28/08/16 07:50, Stone Zhong wrote:

> However, if I have
>          checkToy(() -> {
>              return Arrays.<Integer>asList(10);
>          });
>
> I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?

Do you need the <Integer> qualification on asList?  It seems to work 
without:

import java.util.*;
import java.util.function.*;

public class Funk {
     interface Toy<E> {
         List<E> get();
     }
     
     static void checkToy(Toy<?> toy) { }

     public void test() {
         checkToy(new Toy<Integer>() {
                 @Override
                 public List<Integer> get() {
                     return Arrays.asList(10);
                 }
             });

         checkToy(() -> Arrays.asList(10));
         checkToy(() -> { return Arrays.asList(10); });
     }
}


-- 
ss at comp dot lancs dot ac dot uk

[toc] | [prev] | [next] | [standalone]


#35485

FromStone Zhong <stone.zhong@gmail.com>
Date2016-08-28 03:26 -0700
Message-ID<08a42ed5-5dc2-4e56-a104-6f72ffb75ab8@googlegroups.com>
In reply to#35482
On Saturday, August 27, 2016 at 11:50:40 PM UTC-7, Stone Zhong wrote:
> Hi there, 
> 
> It seems sometimes, the compiler is not smart enough to decide the generic parameter type based on labmda argument types, here is an example:
> 
> I have a interface, say Toy:
> 
> public interface Toy<E> {
>     List<E> get();
> }
> 
> 
> Now I have a method to process toys, such as:
>     public static void checkToy(Toy<?> toy) {
>     }
> 
> Now, the following code works
>         checkToy(new Toy<Integer>() {
>             @Override
>             public List<Integer> get() {
>                 List<Integer> ret = Arrays.asList(10);
>                 return ret;
>             }
>         });
> 
> However, if I have 
>         checkToy(() -> {
>             return Arrays.<Integer>asList(10);
>         });
> 
> I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?
> 
> Thanks,
> Stone

<quote>
Do you need the <Integer> qualification on asList?
</quote>
The point is not to use asList or not, replace "Arrays.<Integer>asList(10)" with any function that returns a List<Integer> will fail as well, you can explicit cast the type, which looks very ugly.

- Stone

[toc] | [prev] | [next] | [standalone]


#35488

FromStone Zhong <stone.zhong@gmail.com>
Date2016-08-28 07:45 -0700
Message-ID<9ff6ad3e-bb82-4207-91d8-f03c707a1dcf@googlegroups.com>
In reply to#35482
On Saturday, August 27, 2016 at 11:50:40 PM UTC-7, Stone Zhong wrote:
> Hi there, 
> 
> It seems sometimes, the compiler is not smart enough to decide the generic parameter type based on labmda argument types, here is an example:
> 
> I have a interface, say Toy:
> 
> public interface Toy<E> {
>     List<E> get();
> }
> 
> 
> Now I have a method to process toys, such as:
>     public static void checkToy(Toy<?> toy) {
>     }
> 
> Now, the following code works
>         checkToy(new Toy<Integer>() {
>             @Override
>             public List<Integer> get() {
>                 List<Integer> ret = Arrays.asList(10);
>                 return ret;
>             }
>         });
> 
> However, if I have 
>         checkToy(() -> {
>             return Arrays.<Integer>asList(10);
>         });
> 
> I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?
> 
> Thanks,
> Stone

<quote>
public static <E> void checkToy(Toy<E> toy) { 
</quote>

Having checkToy take generic parameter is a workaround, but it does not solve the problem which it does not work with <?>. For example, if you have:


    public static void checkToys(Toy<?> ... toys) {
    }

You cannot put a generic type here for checkToys, and you cannot call

        checkToys(
            () -> Arrays.<Integer>asList(10),
            () -> Arrays.<String>asList("hello")
        );

But you can do

        checkToys(
            new Toy<Integer>() {
                @Override
                public List<Integer> get() {
                    return Arrays.<Integer>asList(1, 2, 3);
                }
            },
            new Toy<String>() {
                @Override
                public List<String> get() {
                    return Arrays.<String>asList("a", "b", "c");
                }
            }
        );

[toc] | [prev] | [next] | [standalone]


#35490

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-28 13:22 -0400
Message-ID<npv6l1$9c8$1@gioia.aioe.org>
In reply to#35488
On 8/28/2016 10:45 AM, Stone Zhong wrote:
> Having checkToy take generic parameter is a workaround, but it does not solve the problem which it does not work with <?>. For example, if you have:
>
>
>     public static void checkToys(Toy<?> ... toys) {
>     }
>
> You cannot put a generic type here for checkToys, and you cannot call
>
>         checkToys(
>             () -> Arrays.<Integer>asList(10),
>             () -> Arrays.<String>asList("hello")
>         );
>
> But you can do
>
>         checkToys(
>             new Toy<Integer>() {
>                 @Override
>                 public List<Integer> get() {
>                     return Arrays.<Integer>asList(1, 2, 3);
>                 }
>             },
>             new Toy<String>() {
>                 @Override
>                 public List<String> get() {
>                     return Arrays.<String>asList("a", "b", "c");
>                 }
>             }
>         );

@SuppressWarnings("rawtypes")
public static void checkToys(Toy ... toys) {

Arne

[toc] | [prev] | [next] | [standalone]


#35489

FromStone Zhong <stone.zhong@gmail.com>
Date2016-08-28 07:57 -0700
Message-ID<b0188e32-5d1c-42ff-b670-a25f52314e49@googlegroups.com>
In reply to#35482
On Saturday, August 27, 2016 at 11:50:40 PM UTC-7, Stone Zhong wrote:
> Hi there, 
> 
> It seems sometimes, the compiler is not smart enough to decide the generic parameter type based on labmda argument types, here is an example:
> 
> I have a interface, say Toy:
> 
> public interface Toy<E> {
>     List<E> get();
> }
> 
> 
> Now I have a method to process toys, such as:
>     public static void checkToy(Toy<?> toy) {
>     }
> 
> Now, the following code works
>         checkToy(new Toy<Integer>() {
>             @Override
>             public List<Integer> get() {
>                 List<Integer> ret = Arrays.asList(10);
>                 return ret;
>             }
>         });
> 
> However, if I have 
>         checkToy(() -> {
>             return Arrays.<Integer>asList(10);
>         });
> 
> I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?
> 
> Thanks,
> Stone

I wish java8 allows syntax like
        checkToy(<Integer>() -> {
            return Arrays.<Integer>asList(10);
        });
to help the compiler resolve the generic type when the type has wildcard.

- Stone

[toc] | [prev] | [next] | [standalone]


#35492

FromStone Zhong <stone.zhong@gmail.com>
Date2016-08-28 10:43 -0700
Message-ID<335820fa-8b00-4bb3-8f0a-8f7c7463364c@googlegroups.com>
In reply to#35482
<quote>
@SuppressWarnings("rawtypes") 
public static void checkToys(Toy ... toys) { 
</quote>

It is not always possible or the best approach to use rawtypes,
for example,
say you have a interface called Duck

public interface Duck {
    void squeak();
}

And you need
    public static void checkDuckToys(Toy<? extends Duck> ... toys) {
        for (Toy<? extends Duck> toy : toys) {
            for (Duck duck : toy.get()) {
                duck.squeak();
            }
        }
    }


You can make it
    public static void checkDuckToys(Toy ... toys) {
        Toy<? extends Duck>[] duckToys = (Toy<? extends Duck>[])toys;
        for (Toy<? extends Duck> toy : duckToys) {
            for (Duck duck : toy.get()) {
                duck.squeak();
            }
        }
    }

But it looks pretty ugly.

[toc] | [prev] | [next] | [standalone]


#35505

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-30 20:35 -0400
Message-ID<nq58nu$1qha$1@gioia.aioe.org>
In reply to#35492
On 8/28/2016 1:43 PM, Stone Zhong wrote:
> <quote>
> @SuppressWarnings("rawtypes")
> public static void checkToys(Toy ... toys) {
> </quote>
>
> It is not always possible or the best approach to use rawtypes,
> for example,
> say you have a interface called Duck
>
> public interface Duck {
>     void squeak();
> }
>
> And you need
>     public static void checkDuckToys(Toy<? extends Duck> ... toys) {
>         for (Toy<? extends Duck> toy : toys) {
>             for (Duck duck : toy.get()) {
>                 duck.squeak();
>             }
>         }
>     }

True.

And I can not see any easy workarounds.

But I also think that the case is too rare to consider it a real
problem with Java 8 lambda type inference.

Arne

[toc] | [prev] | [next] | [standalone]


#35538

FromStone Zhong <stone.zhong@gmail.com>
Date2016-09-02 15:18 -0700
Message-ID<811d2fe8-04f6-4784-842c-1e5fb2f7765f@googlegroups.com>
In reply to#35482
On Saturday, August 27, 2016 at 11:50:40 PM UTC-7, Stone Zhong wrote:
> Hi there, 
> 
> It seems sometimes, the compiler is not smart enough to decide the generic parameter type based on labmda argument types, here is an example:
> 
> I have a interface, say Toy:
> 
> public interface Toy<E> {
>     List<E> get();
> }
> 
> 
> Now I have a method to process toys, such as:
>     public static void checkToy(Toy<?> toy) {
>     }
> 
> Now, the following code works
>         checkToy(new Toy<Integer>() {
>             @Override
>             public List<Integer> get() {
>                 List<Integer> ret = Arrays.asList(10);
>                 return ret;
>             }
>         });
> 
> However, if I have 
>         checkToy(() -> {
>             return Arrays.<Integer>asList(10);
>         });
> 
> I got compiling error: "List<Integer> cannot be converted to List<Object>", it seems compiler tried to create a instance of Toy<Object> instead of Toy<Integer> based on the lambda. Is there a wait to tell the compiler it is Toy<Integer> explicitly with the lambda expression?
> 
> Thanks,
> Stone

Just figured you can force type conversion for lambda expression like below and it fixed the problem:

        checkToy(
            (Toy<Integer>) () -> {
                return Arrays.<Integer>asList(1, 2);
            }
        );

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web