Java lambda expressions

Lambda expressions (functions that can be defined anonymously and passed to another function) have been added to Java in the Java 8 version. Lambdas provide elements of fucntional programming, such as the ability to separate a traversal of a data structure from an action performed during that traversal. This allows for writing only one general traversal function and using for various specific tasks by changing the lambda expression that's passed to it.
Below there are a few examples of definitions and use of lambda expressions. There are several Java tutorials on the subject, you are welcome to look at them if you would like to learn more.

Functions that take lambda expressions


import java.util.function.Function;

public class LambdasExample {
	public static void main(String [] args) {
		System.out.println(applyTransformToString((String s) -> s.length()));
		System.out.println(applyTransformToString((String s) -> {
			int count = 0;
				for (int i = 0; i < s.length(); ++i) {
					if (s.charAt(i) == 'n') {
						count++;
					}
				}
			return count;}
			));
		Function<String,Integer> f = countChar('u');
		System.out.println(applyTransformToString(f));
	}
	
	public static int applyTransformToString(Function<String,Integer> transform) {
		String str = "Hello anonymous functions!";
		int result = transform.apply(str);
		return result; 
	}
	
    public static Function<String,Integer> countChar(char c) {
    	return (String s) -> {
			int count = 0;
			for (int i = 0; i < s.length(); ++i) {
				if (s.charAt(i) == c) {
					count++;
				}
			}
		return count;};
    }
	
}

Binary search tree with added general functions


import java.util.ArrayList;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;

/**
 * Binary search tree stores values indexed by keys. Keys must be Comparable and
 * are organized based on their natural ordering (i.e. the ordering given by
 * their compareTo). Values can be of any object type. This tree implementation
 * is not balanced, i.e. it may behave as a linked list in the worst case. Keys
 * may be repeated. Somewhat modeled after Map<K,V> classes in the Java
 * Collections Framework
 * 
 * Author: Elena Machkasova For UMM CSci 2101 class.
 **/

public class BinarySearchTree<K extends Comparable<K>, V> {
        private BSTNode root = null;
        private int count = 0;

        /**
         * @return true if the tree is empty, false otherwise
         **/
        public boolean isEmpty() {
                return root == null;
        }

        /**
         * @return the number of elements in the tree
         **/
        public int size() {
                return count;
        }

        /**
         * Adds a given value indexed with a given key to the tree according to the
         * binary search structure
         * 
         * @param key
         *            - the key of the given element
         * @param value
         *            - the value of the given element
         * @throws NullPointerException if the key is null
         */
        public void put(K key, V value) {       
                if(key == null){
                        throw new NullPointerException();
                }
                if(root == null){
                        root = new BSTNode(key, value);
                        count++;
                }
                else {
                        root.putNode(key, value);
                        count++;
                }
        }
        
        
        /**
         * returns a value associated with the given key in this binary search tree.
         * If multiple values are associated with this key, any one may be returned.
         * If there is no element associated with this key, null is returned.
         * 
         * @param key
         *            - the key to search for.
         * @return - a value to which the specified key is mapped, or null if this
         *         tree contains no mapping for the key
         * @throws NullPointerException if the key is null        
         */
        public V get(K key) {
                if(key == null){
                        throw new NullPointerException();
                } 
                if (root ==null){
                        return null;
                }
                return root.getNode(key);
        }

        /**
         * Removes an element with the given key. The resulting tree is a binary
         * search tree. If there is no such key, the tree is unchanged. If there are
         * multiple values associated with this key, only one is removed. Returns
         * the value associated with this key or null if there is no such value.
         * 
         * @param key
         *            - the key
         * @return - a value to which the specified key is mapped, or null if this
         *         tree contains no mapping for the key
         * @throws NullPointerException if the key is null         
         */
        public V remove(K key) {
                return null;
        }
        
        /**
         * Clears all elements from a given tree.
         * The resulting tree is empty.
         */
        public void clear() {
                root = null;
                count = 0;
        }
        
        /**
         * Returns an array list of key-value pairs for the in-order 
         * traversal of the tree
         * @return - an array list of key-value pairs for the in-order 
         * traversal of the tree
         */
        public ArrayList<KVPair<K,V>> inOrder() {
            ArrayList<KVPair<K,V>> result = new ArrayList<KVPair<K,V>>();
            if (root != null) {
                root.inOrderNode(result);
            }
            return result;
        }
        
        
        /**
         * Returns an array list of key-value pairs that match the specified 
         * criterion on keys and values. The result is accumulated in-order. 
         * @param criterion: a function K, V -> boolean
         * @return an array list of key-value pairs that satisfy a given criterion
         */
        public ArrayList<KVPair<K,V>> selectInOrder(BiPredicate<K,V> criterion) {
        	ArrayList<KVPair<K,V>> result = new ArrayList<KVPair<K,V>>();
        	if (root != null) {
        		root.selectInOrder(criterion, result);
        	}
        	return result;
        }
        
        /**
         * The method takes a function K, V -> V and replaces each value  
         * in the tree with the result of this function. 
         * 
         * @param changeValue: a function K, V -> V to compute the new value 
         *                     based on the key and the old value
         */
        
        public void changeValues(BiFunction<K,V,V> changeValue) {
        	if (root != null) {
        		root.changeValues(changeValue);
        	}
        }

        private class BSTNode {
                public K key;
                public V value;
                public BSTNode left = null;
                public BSTNode right = null;

                // null key will generate a null pointer exception when 
                // a method (such as compareTo) is called on it. 
                // This is fine, according to the JCF specification.
                public BSTNode(K key, V value) {
                        this.key = key;
                        this.value = value;
                }
                
                public void changeValues(BiFunction<K, V, V> changeValue) {
                	if (left != null) {
                		left.changeValues(changeValue);
                	}					
					this.value = changeValue.apply(this.key, this.value);
                	if (right != null) {
                		right.changeValues(changeValue);
                	}											
				}

				public void selectInOrder(BiPredicate<K, V> criterion, ArrayList<KVPair<K,V>> elements) {
                	if (left != null) {
                		left.selectInOrder(criterion, elements);
                	}
					if (criterion.test(this.key, this.value)) {
						elements.add(new KVPair<K,V>(key, value));
					}
                	if (right != null) {
                		right.selectInOrder(criterion, elements);
                	}
				}

				public void putNode(K key, V value) {
                        if (this.key.compareTo(key) <= 0) {
                                if (right == null) {
                                        right = new BSTNode(key, value);
                                }
                                else right.putNode(key, value);
                        }
                        else {
                                if (left == null) {
                                        left = new BSTNode(key, value);
                                }
                                else left.putNode(key, value);
                        }
                }
                public V getNode(K key){
                        if(this.key.compareTo(key) == 0){
                                return this.value;
                        } else if(this.key.compareTo(key) <= 0){
                                if (right == null) {
                                        return null;
                                } else {
                                        return right.getNode(key);      
                                }
                        } else {
                                if (left == null) {
                                        return null;
                                } else {
                                        return left.getNode(key);
                                }
                        }

                }
                
                public void inOrderNode(ArrayList<KVPair<K,V>> elements) {
                    if (left != null) {
                        left.inOrderNode(elements);
                    }
                    elements.add(new KVPair<K,V>(key,value));
                    if (right != null) {
                        right.inOrderNode(elements);
                    }
                }
                
    
        }
}



/**
 * A class for storing key-value pairs generated during
 * traversals of a Binary Search Tree
 * mypair.key gives the key, mypair.value gives the value
 * 
 * @author Elena Machkasova
 *
 * @param <K> - key type (must be comparable to itself)
 * @param <V> - value type 
 */

public class KVPair<K extends Comparable<K>, V> {
        final public K key;
        final public V value;
        
        public KVPair(K key, V value) {
                this.key = key;
                this.value = value;
        }
        
        public boolean equals(Object other) {
                if (! (other instanceof KVPair)) return false;
                KVPair<K,V> otherPair = (KVPair<K,V>) other;
                return (key.equals(otherPair.key) && value.equals(otherPair.value));
        }
        
        public String toString() {
            return "Key: " + key + " Value: " + value + "\n";
        }
}


import java.util.ArrayList;


public class TreeWithLambdas {
	public static void main(String [] args) {
		BinarySearchTree<Integer,String> testTree = new BinarySearchTree<>();
		testTree.put(5,  "elephant");
		testTree.put(3,  "giraffe");
		testTree.put(7,  "zebra");
		testTree.put(2,  "llama");
		testTree.put(8,  "bison");
		
		System.out.println(testTree.selectInOrder(
				(Integer k, String s) -> k % 2 != 0 && s.length() < 8)
				);
		
		System.out.println(testTree.selectInOrder(
				(Integer k, String s) -> s.charAt(s.length() - 1) == 'a')
				);
		
		testTree.changeValues(
				(Integer k, String s) -> s.toUpperCase()
				);
		
		ArrayList<KVPair<Integer,String>> treeElements = testTree.inOrder();
		for (KVPair<Integer,String> treeElement: treeElements) {
			System.out.println(treeElement);
		}
		
		testTree.changeValues(
				(Integer k, String s) -> k.toString()
				);
		
		treeElements = testTree.inOrder();
		for (KVPair<Integer,String> treeElement: treeElements) {
			System.out.println(treeElement);
		}
	}
}


CSci 2101 course web site.