What is the class of method references? - java

I have the following code:
List<Person> personList = getPersons();
List<Function<List<Person>, Stream<Person>>> streams = new ArrayList<>();
streams.add(p -> p.stream());
streams.add(p -> p.parallelStream());
Intellij Idea suggests I should replace the lambda expressions to method references.
I'd like to do so, only I'm not sure what should be the new generic type of the streams list.
I tried to evaluate the expression personList::stream but I get "No such instance field: 'stream'". If I try List::stream or ArrayList::stream (The concrete type of the person list) I get: "No such static field: 'stream'".
Is there a way to add method references to a list?
if so what should be the list's generic type?
Thanks
As assylias pointed out, IDEA was just complaining and the code ran without problem,
I still had problems with the same code in IDEA 13 since streams.add expected a function that returns Stream and List::stream returns Stream. To solve it I ended up using the following code:
List<Person> personList = getPersons();
List<Supplier<Stream<Person>>> streams = new ArrayList<>();
streams.add(personList::stream);
streams.add(personList::parallelStream);

This compiles fine (b119):
List<String> personList = Arrays.asList("a", "b");
List<Function<List<String>, Stream<String>>> streams = new ArrayList<>();
streams.add(List::stream);
streams.add(List::parallelStream);
You may be using an old build of the jdk or IntelliJ is messing with you!

personList::stream is basically the same as p -> p.stream(). Neither has a type per se. The type of the expression is the type of the context that accepts it.

Related

Crossjoin in Cascading

I'd like to crossjoin two streams of tuples in Cascading. Let's suppose there are two lists: ladies and gentlemen, and the goal is to write all the possible lady-gentleman combinations out to a file (e.g. all the possible matches from the "women seeking men" section of a hypothetical dating website).
I found a similar example on this blog and attempted to tweak the code to make a crossjoin (see https://github.com/alexwoolford/cascading-crossjoin-stackoverflow-question).
The operate method in the Crossjoin class throws a null-pointer. Firstly, the getJoinerClosure() call in this line returns null:
JoinerClosure joinerClosure = bufferCall.getJoinerClosure();
... and then the if statement that immediately follows tries to get the size of null:
if( joinerClosure.size() != 2 )
[...]
... resulting in a null-pointer exception.
Can you see where I'm going wrong?
It worked when I removed the rhsGroupFields argument from the new CoGroup constructor, i.e. changed from:
Pipe pipeLadiesAndGentlemen = new CoGroup(pipeLadies, Fields.NONE, pipeGentlemen, Fields.NONE, new Fields("lady", "gentleman"), new BufferJoin());
.. to:
Pipe pipeLadiesAndGentlemen = new CoGroup(pipeLadies, Fields.NONE, pipeGentlemen, Fields.NONE, new BufferJoin());

Collectors.toMap doesn't compile

This code doesn't compile
List<String> pairs = new ArrayList<>();
System.out.println(pairs.stream().collect(Collectors.toMap(x -> x.split("=")[0], x -> x.split("=")[1])));
Compilation error is: The method split(String) is undefined for the type Object
error at System.out.println(pairs.stream().collect(Collectors.toMap(x -> x.split("=")[0], x -> x.split("=")[1])));
But this one compiles fine
List<String> pairs = new ArrayList<>();
Map<String,String> map = pairs.stream().collect(Collectors.toMap(x -> x.split("=")[0], x -> x.split("=")[1]));
System.out.println(map);
Can someone explain why?
MORE INFORMATION
It was intellij 12; jdk1.8.0_11; windows 64
I assume you are using an IDE (like Eclipse). Eclipse - for example - uses its own compiler and does not utilize the "javac" command (from JDK).
So, I can reproduce your problem, but only with Eclipse. Simply compiling this code on command line with "javac" works just fine.
The problem is very simple: The Eclipse compiler is not able to infer the type String for the collect method's arguments. So it simply infers Object (as this is the type, the compiler can safely assume). And an Object does not know the split method.
You can force the compiler to know about String by explicitely declaring the type inside the lambda:
List<String> pairs = new ArrayList<>();
System.out.println(pairs.stream().collect(Collectors.toMap((String x) -> x.split("=")[0], x -> x.split("=")[1])));
... or by explicitely declaring the correct types for the geneirc toMap method:
List<String> pairs = new ArrayList<>();
System.out.println(pairs.stream().collect(Collectors.<String, String, String> toMap(x -> x.split("=")[0], x -> x.split("=")[1])));
Versions of IntelliJ make different(Just red lines in source editor in IDE). The code should be compiled by JDK successfully.
IntelliJ 13 is OK for your code. IntelliJ 12 supports lambda expression poorly. I also met similar problems between two versions of IntelliJ when using lambda expression.

ConcurrentModificationException when invoking putAll

I have difficulties in understanding the following error.
Suppose you have a class A in which I implement the following method:
Map<Double,Integer> get_friends(double user){
Map<Double,Integer> friends = user_to_user.row(user);
//friends.putAll(user_to_user.column(user));
return friends;}
Then in the main I do the following:
A obj = new A();
Map<Double,Integer> temp = obj.get_friends(6);
Well this works fine. However when I uncomment the follwing line in class A:
friends.putAll(user_to_user.column(user));
and I run again the program, it crashes and throws me the concurrentModificationException.
It is to be noted, that I am creating the Table user_to_user as follows:
private HashBasedTable<Double,Double,Integer> user_to_user;//
user_to_user = HashBasedTable.create();
What is further surprising is that when I interchange the way I am filling friends, I mean in that way:
Map<Double,Integer> friends = user_to_user.column(user);
friends.putAll(user_to_user.row(user));
Then everyting will work fine.
Any idea ?
The issue is that HashBasedTable is internally implemented as a Map<Double, Map<Double, Integer>>, and that the implementation of user_to_user.column(user) is iterating over the rows at the same time you're modifying the row associated with user.
One workable alternative would be to copy user_to_user.column(user) into a separate Map before putting it into the row.

how to read a list of objects from the configuration file in play framework

How can i read a list of users from the configuration file in play framework?
i have tried doing something like this:
users=[{uid:123,pwd:xyz},{uid:321,pwd:abc}]
from the play application
List<Object> uids = Play.application().configuration().getList("users");
will give me this a list of objects, if I iterate through the list i get each object as
{uid=123,pwd=xyz} and {uid=321,pwd=abc}
at this point i don't know how i can elegantly get the value of the uid, i can do some hacky job as omit the first and last bracket and parse for the before after equal sign, but it would be too ugly! any idea? (the application is written in java)
thanks
A Scala implementation that avoids the deprecated getConfigList method would rely on retrieving a Seq[Configuration] as follows:
case class UserConfig(uid: Int, pwd: String)
val userConfigs: Seq[UserConfig] = configuration.get[Seq[Configuration]]("users").map { userConfig =>
UserConfig(userConfig.get[Int]("uid"), userConfig.get[String]("pwd"))
}
Since I had recently the same problem and this is still unanswered,
here is my suggestion:
List<User> users = getConfig().getConfigList("users").stream().map(
config -> new User(config.getString("uid"), config.getBoolean("pwd"))
).collect(Collectors.toList());
As far as I know there are no tuples or anything in Java, you need to use either an object or a list with two elements. I decided to go for an object here, you can also return a list.
A list of uid's sounds to me like:
# List of UID's
users=[123,456,789] // every number represents a UID
Then you can get this list as:
List<Object> uids = Play.application().configuration().getList("users");
And then do what you want with this:
for (Iterator<Object> iterator = uids.iterator(); iterator.hasNext();) {
Object object = (Object) iterator.next();
System.out.println(object);
}
Is this what you are looking for?
BTW, you can read more about Play Framework configuration options: http://www.playframework.com/documentation/2.1.0/Configuration

abstractlist protobuf java

I have an object containing a list sent from a C# client to a Java server. The serialization with protobuf work perfectly and the object is received perfectly in Java. But the class generated with protoc.exe (can we call it a proto class?) have a list that i can't modify. Basically, I have to add some values in it before returning it to C#, but when I try to add a value, i have an exception :
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
...
Here's how i'm adding values:
MyProtoObject.MyResult result = MyProtoObject.MyResut.NewBuilder()
.setId(1)
.setValue(9.135)
.build();
MyObject.getResultList().add(result);
How can i insert values in it?
Maybe it's somewhat of a workaround, but you could try this:
List<MyResult> l = new ArrayList<MyResult>(MyObject.getResultList());
l.add(result);
MyObject.setResultList(l);
Ok after regenerating the proto class, it appears some methods was missing (I probably made mistakes in first generation). So now i can add values in the list :
MyObjectProto.MyObject o = MyObjectProto.MyObject.newBuilder()
.addAllResults(listOfCalculations)
.build();
listOfCalculation is a List of results objects
or just :
MyObjectProto.MyObject o = MyObjectProto.MyObject.newBuilder()
.addResult(calculationResult)
.build();
CalculationResult is a single result object
Thanks to Flavio

Categories