Skip to content

Instantly share code, notes, and snippets.

@msfroh
Created December 12, 2011 23:25
Show Gist options
  • Save msfroh/1469633 to your computer and use it in GitHub Desktop.
Save msfroh/1469633 to your computer and use it in GitHub Desktop.
Functional Programming in Java Part 1
final Function2<Integer, Integer, Integer> add =
new Function2<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer i1, Integer i2) {
return i1 + i2;
}
};
// The next two lines output the same thing
System.out.println("4 + 5 = " + add.apply(4, 5));
System.out.println("4 + 5 = " + add.curry().apply(4).apply(5));
output = ListUtils.map(new Function1<Integer, Integer>() {
@Override
public Integer apply(Integer i1) {
return i1 * 2;
}
}).apply(values);
System.out.println(output);
public class FoldExamples {
public static void main(final String[] args) {
List<Integer> values = Arrays.asList(8, 6, 7, 5, 3, 0, 9);
Integer output;
// Find the maximum number
output = ListUtils.foldLeft(new Function2<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer i1, Integer i2) {
return i1 < i2 ? i2 : i1;
}
}).apply(Integer.MIN_VALUE).apply(values);
System.out.println(output);
// Find the sum
output = ListUtils.foldLeft(new Function2<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer i1, Integer i2) {
return i1 + i2;
}
}).apply(0).apply(values);
System.out.println(output);
// Treat list elements as digits and combine to produce
// the resulting integer.
output = ListUtils.foldLeft(new Function2<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer i1, Integer i2) {
return i1 * 10 + i2;
}
}).apply(0).apply(values);
System.out.println(output);
// Concatenate the elements together as a string separated by commas
String sOutput;
sOutput = ListUtils.foldLeft(new Function2<String, String, Integer>() {
@Override
public String apply(String i1, Integer i2) {
final String sep = (i1.length() > 0) ? "," : "";
return i1 + sep + i2.toString();
}
}).apply("").apply(values);
System.out.println(sOutput);
}
}
public class StringLength {
public Integer apply(final String input) {
return input.length();
}
}
// The following outputs 5
System.out.println(new StringLength().apply("hello"));
public abstract class FunctionStringToInteger {
public Integer apply(final String input);
}
final FunctionStringToInteger stringLength = new FunctionStringToInteger() {
@Override
public Integer apply(final String input) {
return input.length();
}
};
// The following outputs 5
System.out.println(stringLength.apply("hello"));
public class ListUtils {
/* ... previous definition of map ... */
// Untyped (raw) foldLeft instance
private static final Function3 rawFoldLeft =
new Function3<Object, Function2, Object, List>() {
@Override
public Object apply(final Function2 func, final Object seed, final List list) {
Object accumulated = seed;
for (Object t : list) {
accumulated = func.apply(accumulated, t);
}
return accumulated;
}
};
// "Factory" method that returns foldLeft function instance with
// appropriate generic type parameters.
public static <R, T1> Function3<R, Function2<R, R, T1>, R, List<? extends T1>>
foldLeftFunc(Class<R> returnClass,
Class<T1> inputClass) {
return rawFoldLeft;
}
// Convenient partial application of foldLeft function where type parameters
// are supplied by the transformation function.
public static <R, T1> Function2<R, R, List<? extends T1>>
foldLeft(final Function2<R, R, T1> function2) {
final Function3<R, Function2<R, R, T1>, R, List<? extends T1>>
foldLeftFunc = rawFoldLeft;
return foldLeftFunc.apply(function2);
}
}
public class ListUtils {
// Untyped (raw) map function instance
private static final Function2 rawMap =
new Function2<List, Function1, List>() {
@Override
public List apply(Function1 func, List list) {
List outputList = new ArrayList(list.size());
for (Object t : list) {
outputList.add(func.apply(t));
}
return outputList;
}
};
// "Factory" method that returns map function instance with
// appropriate generic type parameters.
public static <R, T1> Function2<List<R>, Function1<R, T1>, List<? extends T1>>
mapFunc(Class<R> returnClass,
Class<T1> inputClass) {
return rawMap;
}
// Convenient partial application of map, where type parameters
// are taken from the transformation function.
public static <R, T1>
Function1<List<R>, List<? extends T1>> map(final Function1<R, T1> f1) {
final Function2<List<R>,
Function1<R, T1>,
List<? extends T1>> mapFunc = rawMap;
return mapFunc.apply(f1);
}
}
public class MapExamples {
// Very bad performance if "values" is a LinkedList
public static List<Integer>
doubleListWithIndexes(final List<Integer> values) {
List<Integer> doubledValues = new ArrayList<Integer>();
for (int i = 0; i < values.size(); i++) {
doubledValues.add(values.get(i) * 2);
}
return doubledValues;
}
// Okay. Popular in the pre-1.5 days of Java.
public static List<Integer>
doubleListWithIteratorWhile(final List<Integer> values) {
List<Integer> doubledValues = new ArrayList<Integer>();
Iterator<Integer> iter = values.iterator();
while (iter.hasNext()) {
doubledValues.add(iter.next() * 2);
}
return doubledValues;
}
// Like the example above, but combines two lines into one.
// May be less readable than the "while" version.
public static List<Integer>
doubleListWithIteratorFor(final List<Integer> values) {
List<Integer> doubledValues = new ArrayList<Integer>();
for (Iterator<Integer> iter = values.iterator(); iter.hasNext();) {
doubledValues.add(iter.next() + 2);
}
return doubledValues;
}
// The standard way to do in Java 1.5 or later
public static List<Integer>
doubleListWithForeach(final List<Integer> values) {
List<Integer> doubledValues = new ArrayList<Integer>();
for (Integer value : values) {
doubledValues.add(value * 2);
}
return doubledValues;
}
public static void main(final String[] args) {
List<Integer> values = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> output;
output = doubleListWithIndexes(values);
System.out.println(output);
output = doubleListWithIteratorWhile(values);
System.out.println(output);
output = doubleListWithIteratorFor(values);
System.out.println(output);
output = doubleListWithForeach(values);
System.out.println(output);
}
}
public abstract class Function2<R, T1, T2> {
/* ... previous definition of apply(T1,T2) and curry() ... */
public Function1<R, T2> apply(final T1 t1) {
return curry().apply(t1);
}
}
final Function1<Integer, Integer> addFour = add.apply(4);
System.out.println("4 + 5 = " + addFour.apply(5));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment