• Post Reply Bookmark Topic Watch Topic
  • New Topic

predicates  RSS feed

 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


in the below code, how is the generic type for the Predicate determined , is it through line A ?
because i see that in line A, if i don't use generics to specify String type then line B shows an error !
List<String> bunnies = new ArrayList<>(); //line A
bunnies.add("long ear");
bunnies.add("floppy");
bunnies.add("hoppy");
System.out.println(bunnies); // [long ear, floppy, hoppy]
bunnies.removeIf(s -> s.charAt(0) != 'h'); //line B
System.out.println(bunnies); // [hoppy]

when we we use predicates generally, we are supposed to specify the type right ? otherwise how how java know which class type it has to handle?
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16044
88
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
bunnies is a List of String, and therefore the removeIf() method in line B expects a lamda expression that takes a String - so that is how the type of the variable s is inferred to be String.

If you don't use generics, and you use the raw type List instead, then you just have a list of objects - the compiler doesn't know that it's a list that is supposed to contain only strings, and then the type of s will be inferred to be Object.

Note: you should not use raw types. Always use generics. The only reason that raw types exist is for backward compatibility with old version of Java (Java 1.4 and older). You should only use raw types if it is absolutely necessary, because you are dealing with old code that you cannot change.
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
so the only way that the removeIf() method determines the type of generic for the predicate , is by the type of the ArrayList right ?
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No. You can also explicitly specify the type of the lambda's parameters:
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
And in the case of methods that have additional type parameters, you can supply type arguments explicitly:
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:No. You can also explicitly specify the type of the lambda's parameters:





but if i make the change on line 1 by removing the String generic type, line 6 shows an error !
 
Henry Wong
author
Sheriff
Posts: 23289
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
shambhavi sham wrote:
but if i make the change on line 1 by removing the String generic type, line 6 shows an error ! [/b]


It generates a compiler error because, as Stephan mentioned, the type is specified. And the error is a type mismatch. If you didn't specify the type, then the type would be inferred, and the code will compile.

Keep in mind, that your previous question implied that specifying the type is not an option. Just because you found a case, where you specified the type, and it generates an error, doesn't mean that specifying the type is not an option...

So, you can specify the type -- but you also need to do so without causing a type mismatch.

Henry
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


in the above code , Object and String are causing a mismatch even though String inherits from Object.

but in the below code CharSequence and String don't show any such mismatch . may i know why ?
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Except you don't have an ArrayList<Object>. You have a raw ArrayList. That means removeIf() accepts a raw Predicate. You can't use a lambda expression for a raw Predicate.
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
uh no i don't get you ! can you be more clear please.

 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
How does the compiler know that bunnies is full of Strings? What if I added the following line?
The lambda you passed can not deal with integers, so the compiler is giving off an error.
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
my query deals with these two lines .

CASE 1 : NO ERROR

List<String> bunnies = new ArrayList<>();
bunnies.removeIf((CharSequence s) -> s.charAt(0) != 'h');


CASE 2 : ERROR

List<CharSequence> bunnies = new ArrayList<>();
bunnies.removeIf((String s) -> s.charAt(0) != 'h'); //error



CASE 3 : ERROR
List bunnies = new ArrayList();
bunnies.removeIf((String s) -> s.charAt(0) != 'h'); //error




 
Henry Wong
author
Sheriff
Posts: 23289
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
shambhavi sham wrote:
CASE 1 : NO ERROR

List<String> bunnies = new ArrayList<>();
bunnies.removeIf((CharSequence s) -> s.charAt(0) != 'h');


All String instances are IS-A CharSequence instances.

shambhavi sham wrote:
CASE 2 : ERROR

List<CharSequence> bunnies = new ArrayList<>();
bunnies.removeIf((String s) -> s.charAt(0) != 'h'); //error


All CharSequences instances may *not* be IS-A String instances.

shambhavi sham wrote:
CASE 3 : ERROR
List bunnies = new ArrayList();
bunnies.removeIf((String s) -> s.charAt(0) != 'h'); //error


Raw collections, which deals with Object instances ... and all Object instances may *not* be IS-A String instances.

Henry
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
thanks henry, stephan and jesper !         

bunnies is a List of String, and therefore the removeIf() method in line B expects a lamda expression that takes a String - so that is how the type of the variable s is inferred to be String. this line was in Jesper's answer to my question in this thread. i just want to confirm ,  instead of removeIf() if i were to call some other user defined method that takes a raw Predicate as argument, then where would i have to specify the type i wish to use ? in this case too will it be determined by the object on which this method is called ?

 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Let's do that now.

Now, a raw type is basically the same thing as a parameterized type that uses an unbounded wildcard, except that the compiler doesn't enforce type safety. That means that when you call applyRawPredicate(), you should treat the parameter as a Predicate<?>. The only thing you know for sure about the actual type argument is that it's an Object (because all types inherit from Object). When you want to supply a lambda expression for such a parameter, the lambda's parameter has to be of type Object, and then you'll have to cast it to whatever type you need to deal with:

As you can see, there is no type safety here (what if we had cast to Integer instead?), and the code is just hard to understand and deal with. The lesson? NEVER USE RAW GENERIC TYPES.
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
do you have a similar definition of the removeIf() method ?
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't understand what you mean. Do you want to see how I would implement the removeIf() method if the parameter was a raw predicate?
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
no i want to see when ArrayList<String> arr=new ArrayList();  object is created and then used to call the removeIf() method , how its type is inferred in its constructor ?
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The constructor has no relation to the removeIf() method. You declared arr as an ArrayList<String>, so all occasions of E in the class are substituted with with String. That means that the method signature becomes removeIf(Predicate<String> filter).

There is no type inferred in the constructor call, because you used a raw type again.
 
blossom belle
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK 
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!