DEV Community

Cover image for Java Quickies. Streams and Lambda expressions
Tristan Elliott
Tristan Elliott

Posted on • Updated on

Java Quickies. Streams and Lambda expressions


  • This series is going to be dedicated to the basic understanding of Java. When ever I find myself asking, "How does this work ?". I will create a blog post and put it here. This series will not be in order so feel free to read what ever post you find most relevant.

YouTube version


What we are doing

  • So I am currently working with Spring security and I am using filters, along side json web tokens for authentication. However, I ran into a problem where I want to exclude certain routes from the filters logic. My spaghetti solution to the problem was this:
    protected boolean shouldNotFilter(HttpServletRequest request){
        String path = request.getServletPath();
        String[] urls = {"/api/v1/users/login","/api/v1/users/add"};
        Boolean didPathMatchUrls = -> s.contains(path));
        return didPathMatchUrls; 

Enter fullscreen mode Exit fullscreen mode
  • The method shouldNotFilter() is used to tell the system which paths this filter should not apply to. However I am not really to interested in the method as a whole, this tutorial is all about understanding this line of code:
Boolean didPathMatchUrls = -> s.contains(path));

Enter fullscreen mode Exit fullscreen mode
  • Before we can go any farther we need to first talk about streams

What is a stream?

  • Well streams are an update the the Java API that let us manipulate collections of data in a declarative way. Declarative meaning that we tell the code what to do and not how to do it. However, if you want a more technical definition then here you go: a stream is a sequence of elements from a source that supports data-processing operations.
  • Lets break this statement down a little:

Sequence of elements : a Stream provides an interface to a sequenced(preserving the order) set of values of a specific element type.

Source : Streams need to consume data from a data providing source (like an array)

Data-processing operations : Streams support database like operations and common operations from functional programming languages to manipulate data.

What are streams really doing ?

  • When talking about streams, you could talk and give examples all day long about the data processing operations they enable and the lazy loading optimizations. However, the big difference that makes streams so unique is internal iteration. Which means that traversing each element is handled for us internally by the stream library and we don't have to use a for loop. FYI using a for loop would be considered external iteration. Now, the only way for use to take advantage of internal iteration is if we are provided with predefined operations to work with. .anyMatch() is one such operation.

anyMatch() : this method is used to ask the question, is it true an element in the stream matches the given predicate.

  • This definition might seem particularly unhelpful when we look at our anyMatch method: s -> s.contains(path). To understand what is going on, we need to understand what a Lambda expression is;

What is a Lambda expression?

  • A lambda expression is a, concise representation of an anonymous function that can be passed around. Now that we have the technical jargon out of the way, lets break it down a bit:

Anonymous : we say anonymous because it doesn't have an explicit name like a method would

Function : we say function because a lambda isn't associated with a particular class like a method is.

Passed around : A lambda expression can be passed as an argument to a method or stored in a variable.

Concise : less code to write

  • The term lambda actually comes from lambda calculus ( compsci nerds love lambda calculus)

  • A typical lambda expression(like the one below) has three sections:

s -> s.contains(path)
Enter fullscreen mode Exit fullscreen mode

1) list of parameters
2) an arrow ->
3) the body of the lambda

  • The key to really understanding and using a lambda expression is a functional interface

Functional interface

  • A functional interface is just an interface that specifies an abstract method, it could look something like this:
public interface Testing{
      boolean test(int test`, int test2);
Enter fullscreen mode Exit fullscreen mode
  • Remember that an abstract method that is declared without an implementation(without braces and followed by a semicolon).

  • How do lambdas and functional interfaces work together? A lambda expression lets us provide the implementation of the abstract method inside the functional interface. That might not make much sense now but I will elaborate more in the next section

Type checking

  • If we look as the lambdas that we made previously in this post, you will notice the lack of explicitly declaring types. Don't worry the types are not eliminated, the types used in a lambda are deduced from the context in which the lambda is used in . This type is called the target type. The context is the abstract method that this lambda is implementing.

What is actually happening?

  • So now lets try to break down what is actually happening inside the code for :
anyMatch(s -> s.contains(path))
Enter fullscreen mode Exit fullscreen mode

1) The definition for anyMatch() is looked up

2) it expects an object of type Predicate (target type). You can read the documentation HERE, but the type is String because we are iterating over a stream of Strings

3) Predicate is a functional interface and has a single abstract method called test() documentation HERE

4) We then implement the test() method with our lambda expression. This means that our lambda expression gets is signature from the test() method. So our lambda will take in a single element and return a boolean.

5) We use s.contains(path) to check if the s matches the path and return the boolean.


  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Top comments (0)