Duke Jake Morgan
Duke Jake Morgan

Reputation: 17

Method reference and boolean

So I have been having a go with using the method reference in Java 8 (Object::Method). What I am attempting to do, which I have done before but have forgotten (last time I used this method reference was about 4 months ago), is find the amount of players that != online using the Method Reference.

public static Set<Friend> getOnlineFriends(UUID playerUUID)
{
    Set<Friend> friends = new HashSet<>(Arrays.asList(ZMFriends.getFriends(playerUUID)));

    return friends.stream().filter(Friend::isOnline).collect(Collectors.toSet());
}

public static Set<Friend> getOfflineFriends(UUID playerUUID)
{
    Set<Friend> friends = new HashSet<>(Arrays.asList(ZMFriends.getFriends(playerUUID)));

    return friends.stream().filter(Friend::isOnline).collect(Collectors.toSet());

As you can see I managed to so it when the player (friend) is online but I cannot figure out how to filter though the Set and collect the offline players. I'm missing something obvious, but what is it?!?!

Thanks, Duke.

Upvotes: 0

Views: 1549

Answers (2)

Holger
Holger

Reputation: 298529

In you code

public static Set<Friend> getOnlineFriends(UUID playerUUID)
{
    Set<Friend> friends = new HashSet<>(Arrays.asList(ZMFriends.getFriends(playerUUID)));

    return friends.stream().filter(Friend::isOnline).collect(Collectors.toSet());
}

you are creating a List view to the array returned by ZMFriends.getFriends(playerUUID), copy its contents to a HashSet, just to call stream() on it.

That’s a waste of resources, as the source type is irrelevant to the subsequent stream operation. You don’t need to have a Set source to get a Set result. So you can implement your operation simply as

public static Set<Friend> getOnlineFriends(UUID playerUUID)
{
    return Arrays.stream(ZMFriends.getFriends(playerUUID))
                 .filter(Friend::isOnline).collect(Collectors.toSet());
}

Further, you should consider whether you really need both, getOnlineFriends and getOfflineFriends in your actual implementation. Creating utility methods in advance, just because you might need them, rarely pays off. See also “You aren’t gonna need it”.

But if you really need both operations, it’s still an unnecessary code duplication. Just consider:

public static Set<Friend> getFriends(UUID playerUUID, boolean online)
{
    return Arrays.stream(ZMFriends.getFriends(playerUUID))
                 .filter(f -> f.isOnline()==online).collect(Collectors.toSet());
}

solving both tasks. It still wastes resource, if the application really needs both Sets, as the application still has to perform the same operation twice to get both Sets. Consider:

public static Map<Boolean,Set<Friend>> getOnlineFriends(UUID playerUUID)
{
    return Arrays.stream(ZMFriends.getFriends(playerUUID))
                 .collect(Collectors.partitioningBy(Friend::isOnline, Collectors.toSet()));
}

This provides you both Sets at once, the online friends being associated to true, the offline friends being associated to false.

Upvotes: 2

Shadov
Shadov

Reputation: 5591

There are 2 ways I can think of:

friends.stream().filter(i -> !i.isOnline()).collect(Collectors.toSet());

But I guess that's not what you want, since it's not using a method reference. So maybe something like this:

public static <T> Predicate<T> negation(Predicate<T> predicate) {
    return predicate.negate();
}
...
friends.stream().filter(negation(Friend::isOnline)).collect(Collectors.toSet());

Upvotes: 0

Related Questions