LINQ for Java: LambdaJ

    How often have you seen or written the same few lines of code that are constantly used together to solve the same problem? Take, for example, enumeration or sorting (some manipulation) of collections. Programmers have to write such sections of code every day. Of course, there are various IDEs in which you can use snippets and templates. Nevertheless, such constructions clutter up the code, making it more suitable for computer processing, and not for perception by the programmer.

    Here the LambdaJ library comes to our aid. Its purpose is to simplify the process of working with collections in order to reduce errors in the code and increase its readability by implementing some functional programming techniques without neglecting the static typing of data. The latter fact is extremely important, since static typing is an advantage of the language, significantly increasing the reliability of the code.

    Consider an example using LambdaJ. Find the age of the youngest buyer who made a purchase more than 50'000.

    The classic (iterative) way:
    int age = Integer.MAX_VALUE;
    for (Sale sale : sales) {
      if (sale.getCost() > 50000.00) {
        int buyerAge = sale.getBuyer().getAge();
        if (buyerAge < age)
          age = buyerAge;
      }
    }

    LambdaJ method:
    int age = min(forEach(select(sales, having(
      on(Sale.class).getCost(), greaterThan(50000.00)).getBuyer()))),
      on(Person.class).getAge());


    Functionality



    From the above example, it can be seen that the library provides the programmer with a kind of DSL for working with collections. The domains in this case are java collections, and the language constructs are the statically imported methods of the corresponding classes of the LambdaJ library.

    So what does LambdaJ do? The list of features is approximately the following:
    • filtering elements according to a given condition;
    • change of each element according to a given rule;
    • getting the specified property from each element;
    • sorting elements based on one of the properties;
    • indexing elements based on one of the properties;
    • grouping elements based on one or more properties;
    • calling the specified method for each element;
    • aggregation (for example, summation) of elements or one of their properties;
    • projection (copying) of the properties of one set of objects into the properties of another set of objects (Domain -> DTO);
    • concatenation of the string representation of elements or one of their properties.
    Here you can add work with closures (although, in my opinion, it is better to wait for Java 7 here).


    Examples



    Filtration

    List biggerThan3 = filter(greaterThan(3), asList(1, 2, 3, 4, 5));
    List oldFriends = filter(having(on(Person.class).getAge(), greaterThan(30)), meAndMyFriends);

    Aggregation

    int totalAge = sum(meAndMyFriends, on(Person.class).getAge());

    Getting properties

    List lengths = convert(strings, new PropertyExtractor("length"));
    List ages = extract(persons, on(Person.class).getAge());

    Indexing

    Map personsByName = index(persons, on(Person.class).getFirstName());

    Sorting

    List sorted = sort(persons, on(Person.class).getAge());

    Grouping

    Group group = group(meAndMyFriends, by(on(Person.class).getAge()));
    Group group29aged = group.findGroup("29");


    Performance



    As you know, the pay for convenience is performance. In the case of LambdaJ, overhead is an average of 2.5 times [ * ]. This is certainly sad. However, if the manipulation of collections takes up a small part of the processor time of your application, then the advantages of the convenience of work can significantly outweigh the minus overhead'a.


    PS


    This article is a free translation of arbitrary parts of the official Wiki LambdaJ . More information can be found there.

    Also popular now: