package lambdaex; import java.util.Arrays; import java.util.Comparator; import java.util.function.Function; import java.util.function.IntBinaryOperator; import java.util.function.IntConsumer; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; /* // other class we'll use in an example public class PrintIntStrategy implements IntConsumer { public void accept(int a) { System.out.print(" >" + a); } } */ public class LambdasEx { /* intStream .forEach( void λ(x)) .reduce(initialVal, int λ(previousResult, currentElement)) .reduce(OptionalInt λ(previousResult, currentElement)).getAsInt() .map(int λ(x)) .filter(boolean λ(x)) .sorted() .count() .average().getAsDouble() .max().getAsInt() .min().getAsInt() */ public static void usingIntStreams() { int[] numlist = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // IntStream's of method converts an array to a stream // IntStream's forEach method calls the given method on each element of the array IntStream.of(numlist).forEach(a -> System.out.print(" *" + a)); // IntStream's reduce(int startResult, IntBinaryOperator strategy) // calls strategy.applyAsInt(previousResult, current) // on each element of stream // to get a new result to combine with the next element // add each element y to the total so far x (starts as 0 int total = IntStream.of(numlist).reduce(0, (int x, int y)->{return x + y;}); // without simplifying // since applyAsInt returns int, if just one statement, can leave out return // simplified total = IntStream.of(numlist).reduce(0, (x,y)->x + y); System.out.println("sum = " + total); System.out.println("sum of squares = " + IntStream.of(numlist).reduce(0, (x,y) -> x + y * y)); System.out.println("product = " + IntStream.of(numlist).reduce(1, (x,y ) ->x * y)); //IntStream's map(IntUnaryOperator strategy) // calls strategy.applyAsInt(current) which returns an int // for each element of stream // and makes a new stream out of the results // new stream has all numbers doubled IntStream doubled = IntStream.of(numlist).map((int x) -> {return 2 * x;}); // without simplifying // simplified doubled = IntStream.of(numlist).map(x -> 2 * x); doubled.forEach(x -> System.out.print(x+ ", ")); System.out.println(); // no need for extra variable // just keep using dot operator IntStream.of(numlist) // make an IntStream .map(x -> 2 * x) // map returns an IntStream .forEach(x -> System.out.print(x+ ", ")); // call forEach on that IntStream System.out.println(); // double, then square, then subtract 1, then print IntStream.of(numlist) .map(x -> 2 * x) .map(x -> x * x) .map(x -> x - 1) .forEach(x -> System.out.print(x+ ", ")); System.out.println(); // IntStream's filter(IntPredicate strategy) // applies strategy.test(current) for each element of stream // and adds to new stream if test returned true // filter out only the evens IntStream.of(numlist).filter(x -> x % 2 == 0).forEach(x -> System.out.print(x+ ", ")); System.out.println(); // Intstream's sorted method returns sorted stream, doesn't need strategy int[] rlist = {23, 4, 92, 38, 2, 37, 6,35, 7,8, 0, 7}; IntStream.of(rlist) .sorted() .forEach(x -> System.out.print(x+ ", ")); System.out.println(); //IntStream's average, count, max, min methods don't need strategies // they do what it says on the tin // but average, max, min return OptionalDouble or OptionalInt, need to turn into real thing System.out.println("average of odds = " + IntStream.of(numlist).filter(x -> x % 2 != 0).average().getAsDouble()); System.out.println("max of odds = " + IntStream.of(numlist).filter(x -> x % 2 != 0).max().getAsInt()); System.out.println("min of evens = " + IntStream.of(numlist).filter(x -> x % 2 == 0).min().getAsInt()); System.out.println("how many divisible by 3 = " + IntStream.of(numlist).filter(x -> x % 3 == 0).count()); // array of operators on ints, could also do arraylist for flexibility IntBinaryOperator[] ops = { (x,y)->x+y, // sum (x,y)->x*y, // product (x,y)-> x>y ? x : y, // max (x,y)-> x, // first (x,y)-> y // last }; // apply each operation to the array for (IntBinaryOperator elt : ops) { System.out.println("result: "+ IntStream.of(numlist).reduce(elt)); } } // explaining the new syntax, step by step public static void intStreamSyntaxExample() { int[] numlist = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // make array into stream // "Confusing primitive array passed to vararg method" warning is NetBeans bug IntStream istream = IntStream.of(numlist); // IntStream's forEach(IntConsumer strategy) // calls strategy.apply(current) on each element of stream // give IntStream's forEach a PrintInt as its strategy // which it applies to each int in the stream // so it prints all the ints in the array IntConsumer strategy = new PrintIntStrategy(); istream.forEach(strategy); // "do the strategy on each element of istream" // stream can only be used once anyway, // so usually don't bother with variables // does same as previous two lines IntStream.of(numlist).forEach(new PrintIntStrategy()); // that class is short, and would be easier // if we could see what it does here, so // anonymous class -- create a class to fulfill // interface without naming it // strategy is to print int with > in front IntConsumer anonstrategy = new IntConsumer() { public void accept(int a) { System.out.print(" >" + a); } }; IntStream.of(numlist).forEach(anonstrategy); System.out.println(); // using print, so need extra newline at the end // since we're not using the strategy variable // for anything else, can // put anonymous class right in call to forEach IntStream.of(numlist).forEach( new IntConsumer() { public void accept(int a) { System.out.print(" >" + a); } } ); System.out.println(); // now let's replace that by the lambda syntax // lambda variable hides details of anon class // acts like method reference // new syntax for anonymous method // (parameters) -> {statements} // for IntConsumer we need accept(int a) // so must be (int a) -> {statements of method} IntConsumer printer2 = (int a) -> { System.out.print(" *" + a); }; // but IntConsumer knows what type a has to be // so we can leave out int // if only one parameter, can leave out parens printer2 = a -> { System.out.print(" *" + a); }; // if only one statment, can leave out curly braces and semi printer2 = a -> System.out.print(" *" + a); // remember printer2 is a variable of type IntConsumer // an interface that requires method accept(int x) // which is what the lambda defines the body for printer2.accept(23); System.out.println(); // so printer2 is just like the strategies above // so we can give it to forEach IntStream.of(numlist).forEach(printer2); System.out.println(); // instead of creating the strategy variable printer2 // just use lambda notation in forEach IntStream.of(numlist).forEach(a -> System.out.print(" *" + a)); System.out.println(); // can use :: syntax for existing static methods of right type // creates intConsumer whose apply method just call println IntConsumer printer = System.out::println; IntStream.of(numlist).forEach(printer); IntStream.of(numlist).forEach(System.out::println); } // main to run other methods, more examples public static void main(String[] args) { intStreamSyntaxExample(); usingIntStreams(); } } /* converting incantations int[] → IntStream IntStream istr = IntStream.of(arrayOfInts) IntStream → int int[] = intStream.toArray() ArrayList → Stream ArrayList.stream() → Stream Stream → ArrayList ArrayList arr = (ArrayList)(streamOfT.collect(Collectors.toList())) T[] → Stream Stream str = Arrays.stream(arrayOfT) Stream → T[] T[] tArray = streamOfT.toArray(T[]::new) */ /* IntStream forEach(λ) -- process elements, no return λ: accept(x) →void reduce(start, λ) -- combine elements in order to get int λ: apply(prev, curr) → result map(λ) -- change each element to create new IntStream λ: apply(x) → result filter(λ) -- put elements where λ returns true into new IntStream λ: test(x) → boolean sort() -- sort elements and put in new IntStream count() -- return length of stream max(), min() -- return OptionalInt, .getAsInt() to get int average() -- return OptionalDouble, .getAsDouble to get double */ /* Stream foreach(λ) filter(λ) sorted() // if comparable sorted(Comparator.comparing(λ)) sorted(Comparator.comparing(λ).thenComparing(λ2)) reduce(λ).orElse(emergencyValue) */