Resource Lambda

Discussion in 'Spigot Plugin Development' started by FiXed, May 16, 2016.

  1. [WARNING] If you do not know the basics of Java or do not know how to utilize these features then please do not use them as they will probably make you have errors you don't understand.

    So here today I'll be talking about utilizing lambda and all of it's features, yes it is Java 8 only so if you want to use it you have to use 1.8.

    COLLECTION USAGE (Lists etc):

    It implements a way to create lists of things, and cut them down based on different modifiers, as well as make a for(String string : strings) type statement at the end.
    For this explanation I will be using Bukkit.getOnlinePlayers() just because it's known well here and used widely the variable name for it will be "players"

    First I'll go over the basics, to use Lambda, it's best used with a Collection<T> and I will be displaying the use of that only for now, the simplist thing you can do it use the forEach() function of the collection so here's an example.
    Code (Java):
    players.forEach(player -> player.setHealth(20.0));
    now this code is extremely simple and easy to understand, here we go through all the online players and set their health to 20, for the forEach statement we have player -> , and to explain that it's pretty easy, it's like the for satement, it's basically doing for(Player player : players) for us, and all in one line as well. Pretty cool right? Well we can use it for much more than that.

    Next, I'll go over filtering the players based on a certain boolean that you have set for the players, in this example we will filter them checking if the player has a certain permission.
    Code (Java):
    players.stream().filter(player -> player.hasPermission("permission")).forEach(player -> player.setHealth(20.0));
    You can also use :: to filter, basically Object::bool; Example:
    Code (Java):
    players.stream().filter(Player::isSneaking).forEach(...
    This filtering looks a bit nicer as well, for this though you can't have a method with args for example hasPermission(String permisison) because it has an arg with it, so in turn is invalid to use in this situation.
    So yes, that is quite a nice and long line of code but it all has a purpose, first we call the collection and turn it into a stream, hence the stream() then we filter the stream to only allow players that have the permission "permission" to be in that stream of players, then as stated we set their health to 20, now the boolean in the filter of course can contain && and || and of course == but can also contain a boolean value from a method, it's like a nice if statement, the code behind this for the stream is basically doing this:
    Code (Java):
    for(Player player : players)
      if(player.hasPermission("permission"))
        player.setHealth(20);
    This is not the exact code behind it but it shows a decent example of what is happening while you filter it or so you don't feel limited when using Lambda, be careful when using it because some servers still run Java 7

    So we've filtered it, we've done stuff with it, but what if you just want the plain list? There's a few ways to do this, I'll show them all then explain them.
    Code (Java):
    Collection<? extends Player> players = Bukkit.getOnlinePlayers();
    Collection<Player> filteredPlayers = new ArrayList<Player>();
    players.stream().filter(Player::isSneaking).forEach(filteredPlayers::add);
    // or
    players.stream().filter(player -> player.hasPermission("perm")).forEach(player -> filteredPlayers.add(player));
    // or
    players = players.stream().filter(Player::isSneaking).collect(Collectors.toList());
    So yes all of these work. DO NOT JUST COPY THIS IT WILL CAUSE ERRORS! Now all of these can work separately, the first way is if you want a different list not called players, or if you want to add to a list, the second one works the same way but it just covers it more written out.
    Now the third way returns a Collection<? extends Player> because that's the type of stream it is, this collect method is simple and Collectors.toList() is just a simple way of saying, "make this stream a list" which will do exactly what is wanted, turn the stream into a list. I don't know of a better way to describe it XD

    OTHER FEATURES:

    So in the comments they mention interface parsing, like "runnable", please heavily note that runnable is an INTERFACE not a CLASS.
    For the interface to work with lambda you must have it only have one method, like so:
    Code (Java):
    package lambda;

    public interface Example {

        public void run();

    }
    Having only one function makes it a "functional interface" basically meaning it has one function, this lambda feature is best known as working with runnables but there's quite a few more uses. As you can see in my interface called "Example" I have a method called run, all nice and fine so lets go ahead and implement that method into a class.
    So I've made a class that runs these methods cleanly, I've tested it to make sure I'm right and this is what I came up with:
    Code (Java):
    package lambda;

    public class Lambda {

        public static void main(String[] args) {
            new Lambda().runLambda();
        }

        private final void runLambda() {
            use(() -> System.out.println("Test"));
        }

        private final void use(Example example) {
            example.run();
        }

    }
    Now let's break down this code and figure out what we're trying to do, now when I run this program it will start with the static void main, it creates a new class instance and runs the method called "runLambda" where our lambda feature takes place, now in another method we have use(OurInterface), which will use the interface to use the one method in there, "run", now your IDE should know that the interface only has one method so when using the lambda feature you just need to do () -> method or () -> {} and it will run what's inside the code, now this will then call the use method and have it to Example#run() with the method we setup because that's what we set up. It's basically doing this for the "() -> method" if you know Java basics you should understand why this works:
    Code (Java):
        private final void runLambda() {
            use(new Example(){
                @Override
                public void run() {
                    System.out.println("Test");
                }
            });
        }
    However using lambda will make it much cleaner and easier to read (in my opinion), please note the only way to use this feature is by calling an interface, if you try to call in a class it will not work.

    Main:
    Code (Java):
    package lambda;

    import java.util.Arrays;
    import java.util.Collection;
    import java.util.stream.Collectors;

    public class Lambda {

        public static void main(String[] args) {
            Lambda instance = new Lambda();
            instance.runInterface();
            instance.workWithLists();
        }

        private final void runInterface() {
            use(() -> System.out.println("Interface Example"));
        }

        private final void use(Example example) {
            example.run();
        }

        private final void workWithLists() {
            Collection<String> strings = Arrays.asList("List", "for", "testing", "purposes");
            strings.forEach(e -> System.out.println(e));
            strings.stream().filter(e -> e.contains("o")).forEach(e -> System.out.println("1: " + e));
            strings = strings.stream().filter(e -> e.contains("t")).collect(Collectors.toList());
            strings.forEach(e -> System.out.println("2: " + e));
        }

    }
     
    Interface:
    Code (Java):
    package lambda;

    public interface Example {

        public void run();

    }
     

    This is just a little of what you can do with lambda, only the surface, but I thought I'd give out a nice tutorial of using those features within your plugin. If you think I should add something let me know, I know this thread is a bit short for a resource :)

    PM me if you need help implementing any of this.
     
    #1 FiXed, May 16, 2016
    Last edited: May 22, 2016
    • Like x 7
    • Informative x 3
    • Useful x 2
    • Winner x 1
    • Optimistic x 1
  2. Shouldn't be Lambda?
     
  3. Oh my gosh, didn't notice thanks!
     
    • Useful Useful x 1
  4. Looking good, thanks!
     
  5. Hope it helped you :)
     
  6. Nice guide but i'd recommend you to add how to convert a stream back to a list ;)
     
  7. #Fixed
    ^^
     
  8. He didn't fix it in his actual post ;)
     
  9. Omnivion

    Patron

    Might be worth explaining the double-colon operator too:

    you could filter the above stream to check if a player is sneaking like so:

    Code (Text):
    players.stream().filter(Player::isSneaking)
    I cba to write out an explanation, just thought the code would make for a clear example of something to explain.
     
  10. To be honest, lambda reminds me of php :p(I used to work a bit on Pocketmine plugins shh)
     
  11. That was the joke:oops:
     
  12. Lamba can be used with Runnable and other...

    Code (Java):
    Bukkit.getScheduler().runTask(this, () -> SpawnUtils.spawn(EntityType.SHEEP, UUID.randomUUID());
    ^^'
     
  13. Like I said I didn't add everything, I'll be adding all of those in the near future (have school right now)

    sometimes my internet is slow and I guess it just didn't save the change, it's fixed now (or should be)
     
  14. Serializator

    Supporter

    This isn't enough to explain the new lambda features in Java 8, and I'm almost certain that it isn't enough for the people here who don't really know Java or are learning Java. They should learn this from a source that goes more in depth.

    This isn't to bash your or something, and I like the tutorial, but I don't think it is really a good idea to explain these kind of things on here.
     
    • Agree Agree x 4
  15. By changing the title: "Lambda utility for spigot" it's can resolve the problem because as you said, lambda it's so complete.
     
  16. Ah okay, and yeah I know it's not much but it's what most beginner devs will use for lambda, I do know there are more and I do use more of the features, I didn't want to go fully in depth about lambda because then it would just be a long page for beginner devs to copy code with, honestly explaining all the advanced features of lambda here would not be useful, I agree they should learn Java from a source which goes into depth, I just wanted to cover the basics basically making a starting off point. Similar to how a lot of people start research with wikipedia just to get a basic understanding then move to more in-depth sources. Thanks for you criticism though, I do agree with you.
     
    • Like Like x 1
  17. For this post it's just the basics, I will be adding more and adding more as time goes on, this is mainly just a starting base-thread for this topic, I will be adding more and I will put in a note at the top that tells people they should learn Java in depth before learning the new Lambda features.
     
  18. ~Added
    ~Added

    Hope I added what everyone suggested, I'll add the () -> runnable stuff later (I have to understand it first xD)
     
  19. But isn't this like saying "Don't post java tutorials unless you're going to explain the entirety of java"? :p
     
  20. I don't think that's what he's getting after tbh, I think he's saying I haven't gone in-depth into lambda