通过行为参数化来传递代码
#### example:
假如说你要编写一个筛选绿苹果的函数,你可能会这么写:
import java.util.ArrayList;
import java.util.List;
public class test {
public static List<apple> filter(List<apple> inventory){
List<apple> result = new ArrayList<apple>();
for(apple a:inventory){
if("green".equals(a.getColor())){
result.add(a);
}
}
return result;
}
}
如果这个时候需求改为筛选出质量大于150克的苹果呢?加入需求又改为筛选出红色和绿色而且质量大于150克的苹果呢?
可以根据选择标准建模,我们可以实现一个谓词接口,来返回boolean值.
public interface ApplePredicate{
boolean test(apple apple);
}
public static class AppleRedAndHeavyPredicate implements ApplePredicate{
public boolean test(apple apple){
return "red".equals(apple.getColor())&&apple.getWeight()>150;
}
}
public static List<apple> filter(List<apple> inventory,ApplePredicate p){
List<apple> result = new ArrayList<apple>();
for(apple a:inventory){
if(p.test(a)){
result.add(a);
}
}
return result;
}
那么就可以new 一个谓词对象来做filter方法
List<apple> result = filter(inventory,new AppleRedAndHeavyPredicate());
exam:
编写一个 prettyPrintApple 方法,它接受一个 Apple 的 List ,并可以对它参数化,以
多种方式根据苹果生成一个 String 输出(有点儿像多个可定制的 toString 方法)。例如,你
可 以 告 诉 prettyPrintApple 方 法 , 只 打 印 每 个 苹 果 的 重 量 。 此 外 , 你 可 以 让
prettyPrintApple 方法分别打印每个苹果,然后说明它是重的还是轻的。解决方案和我们
前面讨论的筛选的例子类似。为了帮你上手,我们提供了 prettyPrintApple 方法的一个粗
略的框架
import java.nio.charset.IllegalCharsetNameException;
import java.util.ArrayList;
import java.util.List;
public class printApple {
public interface Predicate{
String accept(apple a);
}
public static class printFancyApple implements Predicate{
public String accept(apple a){
String isHeavy = a.getWeight()>150?"heavy":"light";
return "A "+isHeavy+" "+a.getColor()+" apple";
}
}
public class printSimpleApple implements Predicate{
public String accept(apple a){
return "A "+a.getWeight()+" g "+a.getColor()+" apple";
}
}
public static void printApple(List<apple> Inventory,Predicate p){
for(apple a: Inventory){
String output = p.accept(a);
System.out.println(output);
}
}
public static void main(String [] args)throws Exception{
apple apple1 = new apple("red",160);
apple apple2 = new apple("green",80);
List<apple> inventory = new ArrayList<apple>();
inventory.add(apple1);
inventory.add(apple2);
printApple(inventory,new printFancyApple());
}
}
使用匿名类
那么你就可以实现随时重写filter方法了
List<apple> redApples = filter(inventory, new ApplePredicate() {
@Override
public boolean test(apple apple) {
return "red".equals(apple.getColor());
}
});
使用匿名函数
List<apple> res = filter(inventory,(apple a) -> "red".equals(a.getColor()));
这样更简洁了.
public interface Predicate<T>{
boolean test(T t);
}
public static <T> List<T> filter(List<T>list,Predicate<T>p){
List<T> result = new ArrayList<>();
for(T t:list){
if(p.test(t)){
result.add(t);
}
}
return result;
}
public static void main(String [] args)throws Exception{
apple apple1 = new apple("red",160);
apple apple2 = new apple("green",80);
List<apple> inventory = new ArrayList<apple>();
inventory.add(apple1);
inventory.add(apple2);
List<Integer> numbers = Arrays.asList(1,2,3,4);
List<apple> apples = filter(inventory,(apple a) -> "red".equals(a.getColor()));
List<Integer> evenNums = filter(numbers,(i)-> i%2==0);
}
inventory.sort(new Comparator<apple>(){
@Override
public int compare(apple apple, apple t1) {
return apple.getWeight().compareTo(t1.getWeight());
}
});
inventory.sort((apple a1,apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
Lambda表达式
基本语法:
(parameters) -> expression
(parameters) -> {return xxx;}
在哪里以及如何使用Lambda?
在一些函数式接口可以用lambda函数替代.
函数式接口如下:
public interface Comparator<T>{
int compare(T o1,T o2);
}
public interface Runable{
void run();
}
public interface Callable <V>{
V call();
}
在哪里使用Lambda
execute(()->{});
public void execute(Runnable r){
r.run();
}
Lambda的签名:()->void
这个与runnable中的抽象方法run的签名相匹配
public Callable<String> fetch(){
return () -> "..";
}
Callable定义了一个签名为()->String的方法
与Lambda方法一致
public interfface Predicate{
boolean test(apple a);
}
Predicate<apple> p = (apple a) -> a.getWeight();
函数式接口介绍
下面介绍了Predicate,Consumer,map三种函数是接口的定义以及用法
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class test {
@FunctionalInterface
public interface Predicate<T>{
boolean test(T t);
}
public static <T> List<T> filter(List<T> list,Predicate<T> p){
List<T> result = new ArrayList<>();
for(T t:list){
if(p.test(t)){
result.add(t);
}
}
return result;
}
@FunctionalInterface
public interface Consumer<T>{
void accept(T t);
}
public static <T> void forEach(List<T>list,Consumer<T> c){
for(T i:list){
c.accept(i);
}
}
@FunctionalInterface
public interface Function<T,R>{
R apply(T t);
}
public static<T,R> List<R> map(List<T> list,Function<T,R>f){
List<R> result = new ArrayList<>();
for(T t:list){
result.add(f.apply(t));
}
return result;
}
public static void main(String [] args)throws Exception {
//test Predicate
Predicate<String> nonEmptyPredicate = (String s) -> !s.isEmpty();
List<String> listsOfString = Arrays.asList("","alex","brecher");
List<String> result = filter(listsOfString,nonEmptyPredicate);
Consumer<String> printString = (String s) -> System.out.println(s);
forEach(result,printString);
Function<String,Integer> getLen = (String s) -> s.length();
Function <String,String> flip = (String s) ->{
try{
int i = 0;
int j = s.length()-1;
StringBuilder strBuilder = new StringBuilder(s);
while(i<j){
char temp = s.charAt(i);
strBuilder.setCharAt(i,s.charAt(j));
strBuilder.setCharAt(j,temp);
i++;
j--;
}
return strBuilder.toString();
}finally {
}
};
List<String> flipList = map(result,flip);
List<Integer> lenList = map(result,getLen);
Consumer<Integer> printLen = (Integer i) -> System.out.println(i);
forEach(lenList,printLen);
forEach(flipList,printString);
}
}
result:
alex
brecher
4
7
xela
rehcerb
Java类型分为引用类型和原始类型
前者如(Byte,Integer,Object,List)
后者如(int,double,byte,char)
但是泛型例如Contumer中的T,只能绑定到引用类型.
装箱机制:(boxing)
JAVA中原始类型转换对应的引用类型机制.
拆箱:(unboxing)
JAVA中引用类型转换对应的原始类型机制.
但是自动拆箱和装箱需要更多的内存,性能会受到影响
public interface IntPredicate{
boolean test(int t);
}
IntPredicate evenNumbers = (int i) -> i % 2 ==0; 无装箱
Predicate oddNumbers = (Integer i) -> i %2 ==1; 有装箱
专门输入参数类型的函数式接口的名称都要加上对应的原始类型前缀,如IntPredicate,DoublePredicate
这也叫特化,
方法引用
eg:
public static void main(String [] args)throws Exception {
Consumer<String> printString = (String s) -> System.out.println(s);
List<String> str = Arrays.asList("a","B","A","b");
str.sort((s1,s2) -> s1.compareToIgnoreCase(s2));
List<String> str2 = Arrays.asList("a","b","A","B");
str2.sort(String::compareToIgnoreCase);
forEach(str,printString);
forEach(str2,printString);
}
实战: 用不同的排序策略给一个苹果列表排序
sort函数的签名:
void sort(Comparator<? super E> c)
源码如下:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
public class test {
public static class AppleComparator implements Comparator<Apple> {
public int compare(Apple a1,Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
}
public interface Predicate<Apple>{
boolean test(Apple a);
}
public static void main(String [] args){
//1
List<Apple>inventory = Arrays.asList(new Apple(30,"green"),new Apple(20,"red"),
new Apple(25,"yellow"));
inventory.sort(new AppleComparator());
System.out.println(inventory);
inventory.set(1,new Apple(28,"green"));
//2 自定义函数接口
inventory.sort(new AppleComparator(){
@Override
public int compare(Apple a1,Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
});
System.out.println(inventory);
//3 Lambda
inventory.set(1,new Apple(22,"yellow"));
inventory.sort((Apple a1,Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
System.out.println(inventory);
inventory.set(1,new Apple(32,"red"));
//4 comparing键值
inventory.sort(Comparator.comparing((Apple a)->a.getWeight()));
System.out.println(inventory);
//5.使用方法引用
inventory.set(1,new Apple(33,"red"));
inventory.sort(Comparator.comparing(Apple::getWeight));
System.out.println(inventory);
//6.逆序
inventory.sort(Comparator.comparing(Apple::getWeight).reversed());
System.out.println(inventory);
//7.比较器链 如果两个苹果质量一样,那么比较颜色
inventory.sort(Comparator.comparing(Apple::getWeight)
.reversed()
.thenComparing(Apple::getColor));
}
}