java8-features
Some important Java 8 features: |
|---|
| Contents |
|
1. Functional Interfaces A Functional Interface should contain only one abstract method and can have many default methods. FIs are used to supply logic as variables to lambda expressions and method references, constructor method references instead of objects. FIs are Java way of implementing Functional Programming where logic can be assigned to variable level instead of object. package com.blogspot.codingstreams; interface IFormatting{ public abstract String formatText(String text); } // Normal Approach - Creating Implementation class class UpperCaseFormatting implements IFormatting{ @Override public String formatText(String text) { return text.toUpperCase(); } } public class FunctionalInterfacesDemo { public static void main(String[] args) { // Normal Approach - Creating object that holds the Impl. class logic. IFormatting ucformat = new UpperCaseFormatting(); String formattedText = ucformat.formatText("this is a sample text"); System.out.println(formattedText); // Anonymous Class Approach - Nameless Impl. class. IFormatting lowerCaseFormatting = new IFormatting() { @Override public String formatText(String text) { return text.toLowerCase(); } }; System.out.println(lowerCaseFormatting.formatText("SOME UPPER TEXT.")); } } Output: THIS IS A SAMPLE TEXT some upper text. package com.blogspot.codingstreams; @FunctionalInterface interface IFormatting{ public abstract String formatText(String text); } public class FunctionalInterfacesDemo { public static void main(String[] args) { // Functional Programming Approach IFormatting uppercaseFormatting = (String message) -> message.toUpperCase(); System.out.println(uppercaseFormatting.formatText("SOME mixed cASE Text.")); } } Output: SOME MIXED CASE TEXT. |
|
2. Lambda Expressions Lambda expressions are FP way to implement logic. In Java, Lambdas are used to prevent boilerplate code. Improves code reusability, readability and code looks more compact. Helps to support FP & Streams API in Java. No need to write Impl. classes and their objects for invoking logic. package com.blogspot.codingstreams; interface Greet{ public abstract String greet(String username, int age); } class WelcomeGreet implements Greet{ @Override public String greet(String username, int age) { return "Greetings, "+username+"("+age+"). Welcome to the Java World !"; } } public class LambdaExpressionsTest { public static void main(String[] args) { // Normal way Greet greet = new WelcomeGreet(); System.out.println(greet.greet("Abcd Efgh",23)); // Lambda Expressions way Greet greet2 = (String username, int age) -> { return "Greetings, "+username+"("+age+"). Welcome to the Java World !"; }; System.out.println(greet2.greet("Hjdfh Djfh",25)); // Compact Lambda expression Greet greet3 = (username,age) -> "Greetings, "+username+"("+age+"). Welcome to the Java World !"; System.out.println(greet3.greet("Geff Ktyf",32)); } } Output: Greetings, Abcd Efgh(23). Welcome to the Java World ! Greetings, Hjdfh Djfh(25). Welcome to the Java World ! Greetings, Geff Ktyf(32). Welcome to the Java World ! |
|
3. Method Reference It is shorthand version to refer methods of Functional Interface classes. Makes code compact and improves readability by removing method calling with explicit parameters passing. Used to refer(invoke) static methods, instance methods and constructors. package com.blogspot.codingstreams; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; @FunctionalInterface interface ProcessPairs{ public abstract void printPairs(String k, String v); } public class MethodReferencesTest { public static void main(String[] args) { List // Method reference from String class nums.forEach(System.out::println); Map kvPairs.put("PRIMARY", "RAM"); kvPairs.put("SECONDARY", "HDD"); // Below method reference don't work as println accepts only one param // kvPairs.forEach(System.out::println); // New Impl. to handle k,v pairs ProcessPairs processPairs = (k,v) -> System.out.println("key="+k+", value="+v); kvPairs.forEach(processPairs::printPairs); // Constructor reference Supplier
System.out.println(emptyListSupplier.get()); Supplier String initString = emptyStringSupplier.get(); System.out.println("Init. String: "+initString); } } |
|
4. Stream API Stream is a collection of items that can be processed sequentially or parallelly. Streams can be formed from existing Java collections like lists, maps, arrays, etc. Stream API provides various FP style computational operations that can be performed on a stream. Stream operations are divided into intermediate and terminal operations and chained together to form a pipeline. A Stream pipeline is lazy by default and will be executed only if it has terminal operation. Pipelines produces new stream on executing rather than chaning the original stream. Pipeline executes only once and can not reprocess the same stream. package com.blogspot.codingstreams; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class StreamsTest { public static void main(String[] args) { List // Creating Stream from list Stream Stream filteredStream.forEach(System.out::println); // Parallel stream - Pipeline can be processed parallel by leveraging processor cores Stream // Sequential Stream - converting to sequential stream for batch processing on single core Stream } } |
|
5. Default/Static methods in Interfaces Both static & default methods are used to provide common behavior/functionality without implementation classes. Static methods can not be overidden by Implementation classes, as they are out of scope Default methods can be overidden by the Implementation classes. Default methods provide backward compatibility by not enforcing all the Implementation classes on adding new functionality. package com.blogspot.codingstreams; import java.util.Locale; interface CountryCodeImpl{ // static method to provide common functionality via Interface itself. static String getDefaultCode() { return "KJD-34D-E4F"; } // default methods to provide common functionality via instance. default String getDefaultCodeByLocale(Locale locale) { if(locale == null) return getDefaultCode(); String code = null; switch (locale.getCountry()) { case "IN": code = "IDL-H7G-F3T"; break; case "UK": code = "OKF-VLY-DFK"; break; case "US": code = "LDC-SDO-ODV"; break; default: code = getDefaultCode(); break; } return code; } } public class InterfacesTest { public static void main(String[] args) { // Testing Interface static method String defaultCode = CountryCodeImpl.getDefaultCode(); System.out.println("Default Code:"+defaultCode); // Testing Interface default method // Created anonymous impl. for the Interface CountryCodeImpl countryCodeImpl = new CountryCodeImpl(){}; String usCode = countryCodeImpl.getDefaultCodeByLocale(Locale.US); System.out.println(usCode); // Testing Country locale Locale localeCountry = Locale.getDefault(); System.out.println(countryCodeImpl.getDefaultCodeByLocale(localeCountry)); // Testing default code System.out.println(countryCodeImpl.getDefaultCodeByLocale(null)); } } |
|
6. Optional Classes Option classes are wrapper around the given value to provide extra layer of safety in dealing with null checking. Significantly decreases null checks and can provide default values in case of nulls. Available Optional classes are: Optional generic, OptionalInt, OptionalDouble and OptionalLong package com.blogspot.codingstreams; import java.util.Optional; import java.util.OptionalInt; import java.util.function.Supplier; public class OptionalClassesTest { private static String code = "3434-3482-5344"; private static String noCode = "0000-0000-0000"; private static String noCode() { return noCode; } public static void main(String[] args) { // Wrapping optional class for safety Optional // Safety method to check whether the object has value or not by avoiding Null Pointer Exception. System.out.println(safeCode.isPresent()); //true // Safety methods to derive the value String derivedCode = safeCode.orElse(noCode); System.out.println(derivedCode); //3434-3482-5344 // orElse - Default value when finding null safeCode = Optional.empty(); derivedCode = safeCode.orElse(noCode); System.out.println(derivedCode); //0000-0000-0000 // orElseGet needs supplier Supplier derivedCode = safeCode.orElseGet(noCodeSupplier); System.out.println(derivedCode); //0000-0000-0000 // orElseGet with simple syntax of supplier derivedCode = safeCode.orElseGet(() -> noCode); System.out.println(derivedCode); //0000-0000-0000 // orElseGet with method reference derivedCode = safeCode.orElseGet(OptionalClassesTest::noCode); System.out.println(derivedCode); //0000-0000-0000 int defaultVal = -1; OptionalInt calculatedVal = OptionalInt.of(34); int derivedVal = calculatedVal.orElse(defaultVal); System.out.println("Derived Value is: "+derivedVal); //34 calculatedVal = OptionalInt.empty(); derivedVal = calculatedVal.orElse(defaultVal); System.out.println("Derived Value is: "+derivedVal); //-1 calculatedVal = OptionalInt.of(100); //ifPresent with print consumer calculatedVal.ifPresent(System.out::println); //100 // Another consumer example calculatedVal.ifPresent(n -> System.out.println(n*n)); // 10000 } } |
|
7. Collectors Class Collectors is a helper class in util package helps in summarizing final elements. Provides functionality to aggregate, accumulate and transform the end results from the streams. Acts as reducing job at the last step of Java stream pipeline. package com.blogspot.codingstreams; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; public class CollectorsTest { public static void main(String[] args) { // List of Integer numbers List // List of even numbers List System.out.println(evenNums); // [2, 4, 6, 8, 10, 10, 2, 4, 6, 4, 6] // Set to have unique numbers Set System.out.println(uniqueEvenNums); // [2, 4, 6, 8, 10] // Count the result Long records = nums.stream().collect(Collectors.counting()); System.out.println(records); // 18 // Calculate average Double numsAvg = nums.stream().collect(Collectors.averagingLong(n -> n)); System.out.println(numsAvg); // 5.055555555555555 // Get values as String String numsString = nums.stream().map(n -> String.valueOf(n)).collect(Collectors.joining(",")); System.out.println(numsString); // 1,2,3,4,5,6,7,8,9,10,10,2,3,4,6,1,4,6 // Grouping by value Map |
Comments
Post a Comment