package com.semanticsquare.functional; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import org.htmlcleaner.HtmlCleaner; /** * Demonstrates: * * Function & Predicate (including Chaining & Compose) * Bi-Function as an alternate to Predicate * * Consumer & Supplier * Show API too (including primitive functional interfaces) !! * * Method References * TODO: Constructor References * * @author Dheeru Mundluru * */ public class FunctionalInterfaceDemo { public static void main(String[] args) { String doc1 = "One of the most common uses of streams is to represent queries over data in collections"; String doc2 = "Information integration systems provide valuable services to users by integrating information from a number of autonomous, heterogeneous and distributed Web sources"; String doc3 = "Solr is the popular, blazing fast open source enterprise search platform from the Apache Lucene"; String doc4 = "Java 8 goes one more step ahead and has developed a streams API which lets us think about parallelism"; List documents = new ArrayList<>(Arrays.asList(doc1, doc2, doc3, doc4)); List targetDocuments = new ArrayList<>(); for (String doc : documents) { //boolean isTargetDoc = filter(doc, d -> d.contains("stream")); // 7d: Method References (objectRef::instanceMethod) // Function function = doc::contains; // 4. Implementing Predicate via BiFunction. 'c' is hard-coded in Predicate example BiFunction biFunction = (d, c) -> d.contains(c); // 7c: Method References (ClassName::instanceMethod) // BiFunction biFunction = String::contains; if (biFunction.apply(doc, "stream")) { // if (function.apply("stream")) { //if (isTargetDoc) { // 1. Passing lambda directly doc = transform(doc, d -> Indexer.stripHtmlTags(d)); doc = transform(doc, d -> Indexer.removeStopwords(d)); // 7a. Method References (ClassName::staticMethod) //doc = transform(doc, Indexer::removeStopwords); // 2. Assigning lambda to a variable and then passing as argument //Function htmlCleaner = d -> Indexer.stripHtmlTags(d); //doc = transform(doc, htmlCleaner); //Function stopwordRemover = d -> Indexer.removeStopwords(d); //doc = transform(doc, stopwordRemover); // 3. Compose: andThen & compose return composed functions //Function docProcessor = htmlCleaner.andThen(stopwordRemover); //doc = transform(doc, docProcessor); // System.out.println(doc); targetDocuments.add(doc); } } // Consumer & Supplier Demo System.out.println("\nConsumer & Supplier Demo ... "); // 5. Consumer System.out.println("\nConsumer Demo ... "); targetDocuments.forEach(d -> System.out.println(d)); // 6. Supplier (Deferred Execution). Logging framework ~ java.util.logging uses this System.out.println("\nSupplier Demo ... "); for (String doc : targetDocuments) { try { if (doc.length() > 80) { throw new Exception("Oversized document!!!"); } } catch (Exception e) { // NOTE: doc is being captured from enclosing scope print(() -> e.getMessage() + " ~ " + doc); // 7c. Method References (ClassName::instanceMethod) String resizedDoc = resize(doc, 0, 80, (d, start, end) -> d.substring(start, end)); //String resizedDoc = resize(doc, 0, 80, String::substring); //System.out.println("Resized doc: " + resizedDoc); } } // 7b: Method References (objectRef::instanceMethod) System.out.println("\nMethod References Demo ..."); targetDocuments.forEach(System.out::println); // Constructor References // Typical scenario Supplier supplier = String::new; //() -> new String(); System.out.println("\nsupplier.get: " + supplier.get()); Function function = String::new; //s -> new String(s); System.out.println("\nfunction.apply: " + function.apply("Java")); BiFunction biFunction = HashMap::new; //(c, lf) -> new HashMap(c, lf); System.out.println("\nbiFunction.apply: " + biFunction.apply(100, 0.75f)); Consumer consumer = String::new; consumer.accept("Java"); // Create own interface if existing functional interfaces are not useful! } private static String resize(String doc, int start, int end, TriFunction operator) { doc = operator.apply(doc, start, end); return doc; } private static boolean errorFlag = true; private static void print(Supplier supplier) { if (errorFlag) { System.out.println(supplier.get()); } } static boolean filter(String doc, Predicate filter) { return filter.test(doc); } /*static String transform(String doc, UnaryOperator transformer) { return transformer.apply(doc); }*/ static String transform(String doc, Function transformer) { return transformer.apply(doc); } } class Indexer { private static List stopWords = Arrays.asList("of", "the", "a", "is", "to", "in", "and"); static String stripHtmlTags(String doc) { return new HtmlCleaner().clean(doc).getText().toString(); } static String removeStopwords(String doc) { StringBuilder sb = new StringBuilder(); for (String word : doc.split(" ")) { if (!stopWords.contains(word)) sb.append(word).append(" "); } return sb.toString(); } } @FunctionalInterface interface TriFunction { R apply(S s, U u, V v); }