What's New in Java 8: Lambda Expressions
The biggest new feature of Java 8 is language level support for lambda expressions (Project Lambda). A lambda expression is like syntactic sugar for an anonymous class1 with one method whose type is inferred. However, it will have enormous implications for simplifying development.
1. Syntax
The main syntax of a lambda expression is “parameters -> body”. The compiler can usually use the context of the lambda expression to determine the functional interface2 being used and the types of the parameters. There are four important rules to the syntax:
• Declaring the types of the parameters is optional.
• Using parentheses around the parameter is optional if you have only one parameter.
• Using curly braces is optional (unless you need multiple statements).
• The “return” keyword is optional if you have a single expression that returns a value.
Here are some examples of the syntax:
1 () -> System.out.println(this)
2 (String str) -> System.out.println(str)
3 str -> System.out.println(str)
4 (String s1, String s2) -> { return s2.length() - s1.length(); }
5 (s1, s2) -> s2.length() - s1.length()
The last expression could be used to sort a list; for example:
1 Arrays.sort(strArray,
2 (String s1, String s2) -> s2.length() - s1.length());
In this case the lambda expression implements the Comparator interface to sort strings by length.
2. Scope
Here’s a short example of using lambdas with the Runnable interface:
1 import static java.lang.System.out;
2
3 public class Hello {
4 Runnable r1 = () -> out.println(this);
5 Runnable r2 = () -> out.println(toString());
6
7 public String toString() { return "Hello, world!"; }
8
9 public static void main(String... args) {
10 new Hello().r1.run(); //Hello, world!
11 new Hello().r2.run(); //Hello, world!
12 }
13 }
The important thing to note is both the r1 and r2 lambdas call the toString() method of the Hello class. This demonstrates the scope available to the lambda.
You can also refer to final variables or effectively final variables. A variable is effectively final if it is only assigned once.
For example, using Spring’s HibernateTemplate:
1 String sql = "delete * from User";
2 getHibernateTemplate().execute(session ->
3 session.createSQLQuery(sql).uniqueResult());
In the above, you can refer to the variable sql because it is only assigned once. If you were to assign to it a second time, it would cause a compilation error.
3. Method references
Since a lambda expression is like an object-less method, wouldn’t be nice if we could refer to existing methods instead of using a lamda expression? This is exactly what we can do with method references.
For example, imagine you frequently need to filter a list of Files based on file types. Assume you have the following set of methods for determining a file’s type:
1 public class FileFilters {
2 public static boolean fileIsPdf(File file) {/*code*/}
3 public static boolean fileIsTxt(File file) {/*code*/}
4 public static boolean fileIsRtf(File file) {/*code*/}
5 }
Whenever you want to filter a list of files, you can use a method reference as in the following example (assuming you already defined a method getFiles() that returns a Stream):
1 Stream<File> pdfs = getFiles().filter(FileFilters::fileIsPdf);
2 Stream<File> txts = getFiles().filter(FileFilters::fileIsTxt);
3 Stream<File> rtfs = getFiles().filter(FileFilters::fileIsRtf);
Method references can point to:
• Static methods.
• Instance methods.
• Methods on particular instances.
• Constructors (ie. TreeSet::new)
For example, using the new java.nio.file.Files.lines method:
1 Files.lines(Paths.get("Nio.java"))
2 .map(String::trim)
3 .forEach(System.out::println);
The above reads the file “Nio.java”, calls trim() on every line, and then prints out the lines.
Notice that System.out::println refers to the println method on an instance of PrintStream.
4. Functional Interfaces
In Java 8 a functional interface is defined as an interface with exactly one abstract method. This even applies to interfaces that were created with previous versions of Java.
Java 8 comes with several new functional interfaces in the package, java.util.function.
• Function<T,R> - takes an object of type T and returns R.
• Supplier<T> - just returns an object of type T.
• Predicate<T> - returns a boolean value based on input of type T.
• Consumer<T> - performs an action with given object of type T.
• BiFunction - like Function but with two parameters.
• BiConsumer - like Consumer but with two parameters.
It also comes with several corresponding interfaces for primitive types, such as:
• IntConsumer
• IntFunction<R>
• IntPredicate
• IntSupplier
See the java.util.function Javadocs for more information.
The coolest thing about functional interfaces is that they can be assigned to anything that would fulfill their contract. Take the following code for example:
1 Function<String, String> atr = (name) -> {return "@" + name;};
2 Function<String, Integer> leng = (name) -> name.length();
3 Function<String, Integer> leng2 = String::length;
This code is perfectly valid Java 8. The first line defines a function that prepends “@” to a String. The last two lines define functions that do the same thing: get the length of a String.
The Java compiler is smart enough to convert the method reference to String’s length() method into a Function(a functional interface) whose apply method takes a String and returns an Integer. For example:
1 for (String s : args) out.println(leng2.apply(s));
This would print out the lengths of the given strings.
Any interface can be functional interface, not merely those that come with Java. To declare your intention that an interface is functional, use the @FunctionalInterface annotation. Although not necessary, it will cause a compilation error if your interface does not satisfy the requirements (ie. one abstract method).
Github
See jdk8-lambda-samples for more examples.
5. Comparisons to Java 7
To better illustrate the benefit of Lambda-expressions, here are some examples of how code from Java 7 can be shortened in Java 8.
Creating an ActionListener
1 // Java 7
2 ActionListener al = new ActionListener() {
3 @Override
4 public void actionPerformed(ActionEvent e) {
5 System.out.println(e.getActionCommand());
6 }
7 };
8 // Java 8
9 ActionListener al8 = e -> System.out.println(e.getActionCommand());
Printing out a list of Strings
1 // Java 7
2 for (String s : list) {
3 System.out.println(s);
4 }
5 //Java 8
6 list.forEach(System.out::println);
Sorting a list of Strings
1 // Java 7
2 Collections.sort(list, new Comparator<String>() {
3 @Override
4 public int compare(String s1, String s2) {
5 return s1.length() - s2.length();
6 }
7 });
8 //Java 8
9 Collections.sort(list, (s1, s2) -> s1.length() - s2.length());
10 // or
11 list.sort(Comparator.comparingInt(String::length));
Sorting
For the sorting examples, assume you have the following Person class:
1 public static class Person {
2
3 String firstName;
4 String lastName;
5
6 public String getFirstName() {
7 return firstName;
8 }
9
10 public String getLastName() {
11 return lastName;
12 }
13 }
Here’s how you might sort this list in Java 7 by last-name and then first-name:
1 Collections.sort(list, new Comparator<Person>() {
2 @Override
3 public int compare(Person p1, Person p2) {
4 int n = p1.getLastName().compareTo(p2.getLastName());
5 if (n == 0) {
6 return p1.getFirstName().compareTo(p2.getFirstName());
7 }
8 return n;
9 }
10 });
In Java 8, this can be shortened to the following:
1 list.sort(Comparator.comparing(Person::getLastName)
2 .thenComparing(Person::getFirstName));
This example uses a static method on an interface (comparing) and a default method (thenComparing) which are discussed in the next chapter.
From: https://leanpub.com/whatsnewinjava8/read
...You must Sign up as a member of Effecthub to view the content.
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
2118 views 2 comments
You must Sign up as a member of Effecthub to join the conversation.