· 行为参数化java
· Lambda表达式express
· 概况编程
· 函数式接口数组
· 类型推断app
· 使用外层变量ide
· 方法引用函数式编程
· 复合Lambda表达式函数
1. 理解函数式编程要先理解行为参数化。this
2. 行为参数化:一个方法接受多个不一样的行为做为参数,并在内部使用它们,完成不一样行为的能力。spa
3. 行为参数化优势:可以让代码更好地适应不断变化的需求,减轻将来的工做量。
4. 实现方式
a) Java 8之前:经过接口实现类或接口匿名类实现。
b) Java 8及之后:经过Lambda表达式实现。
5. 举例
a) 经过接口实现类实现行为参数化
i. Apple.java(后续举例将屡次使用到该类)
1 public class Apple { 2 3 private Integer weight; 4 5 private String color; 6 7 public Apple(Integer weight, String color) { 8 this.weight = weight; 9 this.color = color; 10 } 11 12 public Integer getWeight() { 13 return weight; 14 } 15 16 public void setWeight(Integer weight) { 17 this.weight = weight; 18 } 19 20 public String getColor() { 21 return color; 22 } 23 24 public void setColor(String color) { 25 this.color = color; 26 } 27 28 @Override 29 public String toString() { 30 return "weight=" + weight + " color=" + color; 31 } 32 }
ii. ApplePredicate.java
1 public interface ApplePredicate { 2 3 boolean test(Apple apple); 4 5 }
iii. AppleHeavyWeightPredicate.java
1 public class AppleHeavyWeightPredicate implements ApplePredicate { 2 3 public boolean test(Apple apple) { 4 return apple.getWeight() > 150; 5 } 6 7 }
iv. AppleGreenColorPredicate.java
1 public class AppleGreenColorPredicate implements ApplePredicate { 2 3 public boolean test(Apple apple) { 4 return "green".equals(apple.getColor()); 5 } 6 7 }
v. Test.java
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 5 public class Test { 6 7 public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) { 8 List<Apple> result = new ArrayList<>(); 9 for (Apple apple : inventory) { 10 if (p.test(apple)) { 11 result.add(apple); 12 } 13 } 14 return result; 15 } 16 17 public static void printApples(List<Apple> inventory) { 18 for (Apple apple : inventory) { 19 System.out.println(apple); 20 } 21 } 22 23 public static void main(String[] args) { 24 List<Apple> inventory = Arrays.asList( 25 new Apple(100, "red"), 26 new Apple(110, "red"), 27 new Apple(190, "red"), 28 new Apple(170, "red"), 29 new Apple(100, "green"), 30 new Apple(120, "green"), 31 new Apple(160, "green"), 32 new Apple(180, "green") 33 ); 34 List<Apple> newInventory1 = filterApples(inventory, new AppleHeavyWeightPredicate()); 35 printApples(newInventory1); 36 System.out.println("-----"); 37 List<Apple> newInventory2 = filterApples(inventory, new AppleGreenColorPredicate()); 38 printApples(newInventory2); 39 } 40 41 }
b) 经过接口匿名类实现行为参数化
i. ApplePredicate.java
1 public interface ApplePredicate { 2 3 boolean test(Apple apple); 4 5 }
ii. Test.java
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 5 public class Test { 6 7 public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) { 8 List<Apple> result = new ArrayList<>(); 9 for (Apple apple : inventory) { 10 if (p.test(apple)) { 11 result.add(apple); 12 } 13 } 14 return result; 15 } 16 17 public static void printApples(List<Apple> inventory) { 18 for (Apple apple : inventory) { 19 System.out.println(apple); 20 } 21 } 22 23 public static void main(String[] args) { 24 List<Apple> inventory = Arrays.asList( 25 new Apple(100, "red"), 26 new Apple(110, "red"), 27 new Apple(190, "red"), 28 new Apple(170, "red"), 29 new Apple(100, "green"), 30 new Apple(120, "green"), 31 new Apple(160, "green"), 32 new Apple(180, "green") 33 ); 34 List<Apple> newInventory1 = filterApples(inventory, new ApplePredicate() { 35 @Override 36 public boolean test(Apple apple) { 37 return apple.getWeight() > 150; 38 } 39 }); 40 printApples(newInventory1); 41 System.out.println("-----"); 42 List<Apple> newInventory2 = filterApples(inventory, new ApplePredicate() { 43 @Override 44 public boolean test(Apple apple) { 45 return "green".equals(apple.getColor()); 46 } 47 }); 48 printApples(newInventory2); 49 } 50 51 }
1. Lambda表达式:可把Lambda表达式看做只有一个方法的接口匿名类,即没有声明名称的方法,也能够做为参数传递给另外一个方法。
2. Lambda表达式特色
a) 匿名:不像普通的方法那样有一个明确的名称。
b) 函数:不像方法那样属于某个特定的类。但和方法同样,Lambda有参数列表、函数主体、返回类型,还可能有能够抛出的异常列表。
c) 传递:能够做为参数传递给方法或存储在变量中。
d) 简洁:无需像匿名类那样写不少模板代码。
3. Lambda表达式语法
a) 语法格式1
(parameters) -> expression
b) 语法格式2
(parameters) -> { statements; }
c) 举例
场景 |
Lambda表达式 |
布尔表达式 |
(List<String> list) -> list.isEmpty() |
建立对象 |
() -> new Apple(10, "red") |
消费一个对象 |
(Apple a) -> { System.out.println(a.getWeight()); } |
从一个对象中选择/抽取 |
(String s) -> s.length() |
组合两个值 |
(int a, int b) -> a * b |
比较两个对象 |
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()) |
4.Lambda表达式使用条件:只能在函数式接口上使用。
5.函数式接口(Functional Interface):只定义一个抽象方法的接口(注意不包括默认方法)。
6.举例:经过Lambda表达式实现行为参数化
a) ApplePredicate.java
1 public interface ApplePredicate { 2 3 boolean test(Apple apple); 4 5 }
b) Test.java
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 5 public class Test { 6 7 public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) { 8 List<Apple> result = new ArrayList<>(); 9 for (Apple apple : inventory) { 10 if (p.test(apple)) { 11 result.add(apple); 12 } 13 } 14 return result; 15 } 16 17 public static void printApples(List<Apple> inventory) { 18 for (Apple apple : inventory) { 19 System.out.println(apple); 20 } 21 } 22 23 public static void main(String[] args) { 24 List<Apple> inventory = Arrays.asList( 25 new Apple(100, "red"), 26 new Apple(110, "red"), 27 new Apple(190, "red"), 28 new Apple(170, "red"), 29 new Apple(100, "green"), 30 new Apple(120, "green"), 31 new Apple(160, "green"), 32 new Apple(180, "green") 33 ); 34 List<Apple> newInventory1 = filterApples(inventory, (Apple apple) -> apple.getWeight() > 150); 35 printApples(newInventory1); 36 System.out.println("-----"); 37 List<Apple> newInventory2 = filterApples(inventory, (apple) -> "green".equals(apple.getColor())); 38 printApples(newInventory2); 39 } 40 41 }
1. Java 8自带的函数式接口都在java.util.function包下。
2. 异常:Java 8自带函数式接口都不容许抛出Checked Exception。若是须要Lambda表达式来抛出异常,要么定义一个本身的函数式接口,并声明Checked Exception,要么把Lambda包在一个try/catch块中。
3. 装箱操做(Boxing):为了不装箱操做带来的开销问题,不该使用Predicate<T>或Function<T, R>等通用函数式接口,而应使用IntPredicate、IntToLongFunction等原始类型特化接口。
4. Java 8经常使用函数式接口
函数式接口 |
函数描述符 |
原始类型特化 |
Predicate<T> |
T->boolean |
IntPredicate LongPredicate DoublePredicate |
Consumer<T> |
T->void |
IntConsumer LongConsumer DoubleConsumer |
Function<T,R> |
T->R |
IntFunction<R> IntToDoubleFunction IntToLongFunction LongFunction<R> LongToDoubleFunction LongToIntFunction DoubleFunction<R> ToIntFunction<T> ToDoubleFunction<T> ToLongFunction<T> |
Supplier<T> |
()->T |
BooleanSupplier IntSupplier LongSupplier DoubleSupplier |
UnaryOperator<T> |
T->T |
IntUnaryOperator LongUnaryOperator DoubleUnaryOperator |
BinaryOperator<T> |
(T,T)->T |
IntBinaryOperator LongBinaryOperator DoubleBinaryOperator |
BiPredicate<L, R> |
(L, R) -> boolean |
|
BiConsumer<T, U> |
(T, U) -> void |
ObjIntConsumer<T> ObjLongConsumer<T> ObjDoubleConsumer<T> |
BiFunction<T, U, R> |
(T, U) -> R |
ToIntBiFunction<T, U> ToLongBiFunction<T, U> ToDoubleBiFunction<T, U> |
5. 举例
a) Lambda表达式与函数式接口对应
场景 |
Lambda表达式 |
对应的函数式接口 |
布尔表达式 |
(List<String> list) -> list.isEmpty() |
Predicate<List<String>> |
建立对象 |
() -> new Apple(10, "red") |
Supplier<Apple> |
消费一个对象 |
(Apple a) -> { System.out.println(a.getWeight()); } |
Consumer<Apple> |
从一个对象中选择/抽取 |
(String s) -> s.length() |
Function<String, Integer>或 ToIntFunction<String> |
组合两个值 |
(int a, int b) -> a * b |
IntBinaryOperator |
比较两个值 |
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()) |
Comparator<Apple> 或 BiFunction<Apple, Apple, Integer> 或 ToIntBiFunction<Apple, Apple> |
b) Predicate<T>
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 import java.util.function.Predicate; 5 6 public class Test { 7 8 public static <T> List<T> filter(List<T> list, Predicate<T> p) { 9 List<T> results = new ArrayList<>(); 10 for (T s : list) { 11 if (p.test(s)) { 12 results.add(s); 13 } 14 } 15 return results; 16 } 17 18 public static void main(String[] args) { 19 List<String> listOfStrings = Arrays.asList("", "A", "B", "", "C"); 20 Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty(); 21 List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate); 22 for (String string : nonEmpty) { 23 System.out.println(string); 24 } 25 } 26 27 }
c) Consumer<T>
1 import java.util.Arrays; 2 import java.util.List; 3 import java.util.function.Consumer; 4 5 public class Test { 6 7 public static <T> void forEach(List<T> list, Consumer<T> c){ 8 for(T i: list){ 9 c.accept(i); 10 } 11 } 12 13 public static void main(String[] args) { 14 List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4, 5); 15 forEach(listOfNumbers, (Integer i) -> System.out.println(i)); 16 } 17 18 }
d) Function<T, R>
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 import java.util.function.Function; 5 6 public class Test { 7 8 public static <T, R> List<R> map(List<T> list, Function<T, R> f) { 9 List<R> result = new ArrayList<>(); 10 for(T s: list){ 11 result.add(f.apply(s)); 12 } 13 return result; 14 } 15 16 public static void main(String[] args) { 17 List<String> listOfStrings = Arrays.asList("lambdas", "in", "action"); 18 List<Integer> l = map(listOfStrings, (String s) -> s.length()); 19 for (Integer i : l) { 20 System.out.println(i); 21 } 22 } 23 24 }
1. 类型推断:同一个Lambda表达式就可赋予不一样的函数式接口,只要它们的抽象方法签名可以兼容。
1 Callable<Integer> c = () -> 42; 2 PrivilegedAction<Integer> p = () -> 42;
1 Comparator<Apple> c1 = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()); 2 ToIntBiFunction<Apple, Apple> c2 = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()); 3 BiFunction<Apple, Apple, Integer> c3 = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
2. void兼容规则:若是一个Lambda的主体是一个语句表达式, 它就和一个返回void的函数描述符兼容(固然须要参数列表也兼容)。例如,虽然List.add方法返回boolean,但Consumer<T>的T->void仍然兼容。
Consumer<String> b = s -> list.add(s);
3. Object类:Object不是函数式接口。下面的代码没法编译。
Object o = () -> {System.out.println("Tricky example"); };
4. Lambda表达式类型省略
a) 参数类型省略:省略和不省略均可能更易读。
1 // 没有类型推断 2 Comparator<Apple> c = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()); 3 // 有类型推断 4 Comparator<Apple> c = (a1, a2) -> a1.getWeight().compareTo(a2.getWeight());
b) 参数括号省略:当Lambda仅有一个类型须要推断的参数时,参数名称两边的括号也能够省略。
List<Apple> greenApples = filter(inventory, a -> "green".equals(a.getColor()));
1. 外层变量限制:Lambda表达式只能使用显式声明为final或其实是final的外层变量。与匿名类相似,但匿名类更严格(只能使用显式声明为final的外层变量)。
2. 限制缘由
a) Lambda表达式在访问外层变量时,其实是在访问它的副本,而不是访问原始变量。
b) 函数式编程不鼓励使用外层变量(更容易并行)。
3. 举例
a) 可正常运行
1 int number = 100; 2 Runnable r = () -> System.out.println(number); 3 new Thread(r).start();
b) 运行报错“local variables referenced from a lambda expression must be final or effectively final”
1 int number = 100; 2 Runnable r = () -> System.out.println(number); 3 new Thread(r).start(); 4 number = 200;
1. 方法引用:能够重复使用现有的方法定义,并像Lambda同样传递。
2. 方法引用优势:有时比Lambda表达式可读性更好。
3. 方法引用的种类
a) 指向静态方法的方法引用,例如Integer.parseInt()方法,写做Integer::parseInt。
b) 指向任意类型实例方法的方法引用,例如String.length()方法,写做String::length。
c) 指向现有对象的实例方法的方法引用,例若有一个局部变量apple有getWeight()实例方法,apple::getWeight。
d) 指向构造函数的方法引用,例如Date的构造方法,写做Date::new。
e) 针对构造函数、数组构造函数和父类调用(super-call)的一些特殊形式的方法引用。
4. 举例
a) Lambda表达式与方法引用对应
Lambda表达式 |
对应的方法引用 |
(Apple a) -> a.getWeight() |
Apple::getWeight |
() -> Thread.currentThread().dumpStack() |
Thread.currentThread()::dumpStack |
(str, i) -> str.substring(i) |
String::substring |
(String s) -> System.out.println(s) |
System.out::println |
() -> new Date() |
Date::new |
b) 指向现有对象的实例方法的方法引用
1 import java.util.Arrays; 2 import java.util.List; 3 4 import static java.util.Comparator.comparing; 5 6 public class Test { 7 8 public static void printApples(List<Apple> inventory) { 9 for (Apple apple : inventory) { 10 System.out.println(apple); 11 } 12 } 13 14 public static void main(String[] args) { 15 List<Apple> inventory = Arrays.asList( 16 new Apple(100, "red"), 17 new Apple(110, "red"), 18 new Apple(190, "red"), 19 new Apple(170, "red"), 20 new Apple(100, "green"), 21 new Apple(120, "green"), 22 new Apple(160, "green"), 23 new Apple(180, "green") 24 ); 25 // i.e. inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())); 26 // i.e. inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight())); 27 inventory.sort(comparing(Apple::getWeight)); 28 printApples(inventory); 29 } 30 31 }
c) 指向构造函数的方法引用
1 import java.util.Date; 2 import java.util.function.Function; 3 import java.util.function.Supplier; 4 5 interface TriFunction<T, U, V, R>{ 6 R apply(T t, U u, V v); 7 } 8 9 public class Test { 10 11 public static void main(String[] args) { 12 Supplier<Date> s = Date::new; // i.e. () -> new Date() 13 Date d1 = s.get(); 14 System.out.println(d1); 15 16 Function<Long, Date> f = Date::new; // i.e. (Long l) -> new Date(l) 17 Date d2 = f.apply(0L); 18 System.out.println(d2); 19 20 TriFunction<Integer, Integer, Integer, Date> tf = Date::new; 21 Date d3 = tf.apply(2000, 1, 1); 22 System.out.println(d3); 23 } 24 25 }
1. 复合Lambda表达式:把多个简单的Lambda表达式复合成复杂的表达式,好比使用and、or复合。
2. 举例
a) Comparator复合
1 import java.util.Arrays; 2 import java.util.List; 3 4 import static java.util.Comparator.comparing; 5 6 public class Test { 7 8 public static void printApples(List<Apple> inventory) { 9 for (Apple apple : inventory) { 10 System.out.println(apple); 11 } 12 } 13 14 public static void main(String[] args) { 15 List<Apple> inventory = Arrays.asList( 16 new Apple(100, "red"), 17 new Apple(110, "red"), 18 new Apple(190, "red"), 19 new Apple(170, "red"), 20 new Apple(100, "green"), 21 new Apple(120, "green"), 22 new Apple(160, "green"), 23 new Apple(180, "green") 24 ); 25 inventory.sort( 26 comparing(Apple::getWeight) 27 .reversed() 28 .thenComparing(Apple::getColor) 29 ); 30 printApples(inventory); 31 } 32 33 }
b) Predicate复合
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 import java.util.function.Predicate; 5 6 public class Test { 7 8 public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) { 9 List<Apple> result = new ArrayList<>(); 10 for (Apple apple : inventory) { 11 if (p.test(apple)) { 12 result.add(apple); 13 } 14 } 15 return result; 16 } 17 18 public static void printApples(List<Apple> inventory) { 19 for (Apple apple : inventory) { 20 System.out.println(apple); 21 } 22 } 23 24 public static void main(String[] args) { 25 List<Apple> inventory = Arrays.asList( 26 new Apple(100, "red"), 27 new Apple(110, "red"), 28 new Apple(190, "red"), 29 new Apple(170, "red"), 30 new Apple(100, "green"), 31 new Apple(120, "green"), 32 new Apple(160, "green"), 33 new Apple(180, "green") 34 ); 35 Predicate<Apple> p = a -> "red".equals(a.getColor()); 36 p = p.negate() 37 .and(a -> a.getWeight() > 150) 38 .or(a -> a.getWeight() <= 110); 39 List<Apple> newInventory = filterApples(inventory, p); 40 printApples(newInventory); 41 } 42 43 }
c) 函数复合
1 import java.util.function.Function; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 Function<Integer, Integer> f = x -> x + 1; 7 Function<Integer, Integer> g = x -> x * 2; 8 9 Function<Integer, Integer> h1 = f.andThen(g); // i.e. g(f(x)) 10 int result1 = h1.apply(1); 11 System.out.println(result1); // 4 12 13 Function<Integer, Integer> h2 = f.compose(g); // i.e. f(g(x)) 14 int result2 = h2.apply(1); 15 System.out.println(result2); // 3 16 } 17 18 }
做者:netoxi
出处:http://www.cnblogs.com/netoxi本文版权归做者和博客园共有,欢迎转载,未经赞成须保留此段声明,且在文章页面明显位置给出原文链接。欢迎指正与交流。