sap界面功能
目录
1.简介
函数接口是Java 8提供的强大机制,使我们可以将函数作为参数传递给其他方法。 实际上,此选项在Java的早期版本中已经存在,例如,具有接口Comparator。
什么是功能接口? 功能接口定义了“对象”,它们不像传统对象那样存储值,而仅存储“功能”。 请注意,“对象”和“功能”都在引号之间,这是因为功能接口不是实际的对象或功能,而仅仅是一种机制,该机制具有一种方法来接收功能元素作为参数。 让我们回顾一下Comparator界面:Comparator定义了什么? 定义了自然排序标准,以使compare方法告诉我们两个给定对象中的哪个可以视为较小对象。 如果将Comparator对象传递给方法,则我们将为该方法提供能够告知对象顺序的函数。 该方法相对于此排序是“通用的”,必须准备好接收任何条件并根据输入的排序执行其功能。
这样,例如,来自Collections类的sort方法可以接收Comparator类型的对象。 以前,必须已经实现了Comparator类型的类来定义要比较的类的对象的顺序。
例。 根据价格从大到小的顺序排列航班的Comparator类是:
public class ComparatorFlightPrice implements Comparator<Flight> {
public int compare(Flight v1, Flight v2){
return v1.getPrice().compareTo(v2.getPrice());
}
}
调用可能是:
Collections.sort(flightList, new ComparatorFlightPrice());
可以看出,由于接收到的Comparator对象告诉sort必须如何对flightList中的值进行排序,因此sort方法将接收一个函数类型参数。 很明显,必须准备Collections类的sort方法的代码以在不同条件下进行排序。 为此,sort方法在其代码行中具有对其作为参数接收的对象的compare方法的一般调用。 这样,如果它收到按价格定购的比较器,它将按航班价格定购输入清单,而如果通过旅客编号传递的比较器定单,这将成为订购标准。
Java 8的作用是扩展功能接口的数量及其可用性,以定义一组参数为这些接口的方法。
2.理由
让我们研究不同于Comparator的功能接口的另一种可能的应用。 有很多算法在其方案中使用布尔条件。 最简单的例子之一是计数器算法模式,该模式返回满足一定条件的集合中元素的数量:今天有多少次完整航班起飞? 本周有几班飞往马德里的航班? 等等。我们知道此算法的方案如下:
Scheme counter
Initiate counter
For each element in collection
If condition
Increment counter
EndIf
EndFor
Return counter
}
该方案将元素收集和必须验证的条件作为输入,并将计数器作为输出。 例如,让我们看一下来自Airport的方法,该方法计算了前往特定目的地的航班数量和特定日期之后的航班数量。
public Integer counterFlightsDate(Date f){
Integer counter=0;
for(Flight v:flights){
if (v.getDate().compareTo(f)>0){
counter++;
}
}
return counter;
}
public Integer counterFlightsDestination(String d){
Integer counter =0;
for(Flight v:flights){
if (v.getDestination().equals(d)){
counter ++;
}
}
return counter;
}
显然,除了条件和参数类型外,这两种方法的代码完全相同:第一种情况的Date f和第二种情况的目标String d。 此代码将按以下方式调用:
Integer cont1 = SVQairport.counterFlightsDate("Madrid");
System.out.println("The number of flights to Madrid is "+cont1);
Integer cont2 = SVQairport.counterFlightsDestination(new Date(16,07,2014));
System.out.println("The number of flights later than 16th of July is "+cont2);
让我们假设我们可以通过在“ if”上指定的条件作为参数。 然后,方法代码可以概括为:
public Integer genericalFlightCount(Condition<Flight> filter){
Integer counter=0;
for (Flight v:flights){
if (condition of filter over v){
counter ++;
}
}
return counter;
}
第1行:稍后,此假设类型的Condition实际上将是谓词类型
第4行:此表达式实际上是filter.test(v),因为这是Predicate中实现的方法
这样,我们将拥有一个针对Airport的通用计数器方法,该方法一旦编码,便可以使用不同的布尔表达式调用并具有不同的功能。 为了能够将布尔表达式作为参数传递,我们需要一个类型(接口)条件,该条件将实现方法的接收和所涉及类型的对象(在这种情况下为Flight),并返回一个布尔类型的值符合要求的条件。 功能接口谓词就是这种可能性,它将是下一部分要研究的第一个示例。
该通用方法的调用为:
Integer cont1 = SVQairport.genericalFlightCount(v-> v.getDestination.equals("Madrid"));
System.out.println("The number of flights from Madrid is "+cont1);
Date f = new Date(16,07,2014)
Integer cont2 = SVQairport.genericalFlightCount
(v->v.getDate().compareTo(f)>0);
System.out.println("The number of flights later than 16th of July is "+cont2);
第1行:这是一个lambda表达式(请参阅下一部分),它表示作为参数传递的“条件”或“过滤器”表示每个Flight v返回有关其目的地是否为Madrid的条件
第6行:这是另一个lambda表达式,对于每个Flight v,如果出发日期晚于7月14日,则返回true
3. Lambda表达式
Java 8还有另外一点变化,那就是将功能接口作为方法的参数提供的方式。 如上例所示,为了在Java7中使用Comparator,定义了一个包含compare方法的外部类,并且该类的对象在调用时或通过先前创建的方法传递给需要它的方法目的。 Java 8还有其他更灵活的机制来定义功能接口:lambda表达式和方法引用。
Lambda表达式是一种方法的简化,其中输入参数和输出表达式由箭头运算符'->'分隔。 输入参数写在方括号之间,并用逗号分隔。 如果接口具有单个输入参数,则不需要括号。 因此,lambda表达式的第一部分的形状将类似于()->如果没有输入参数,则x->如果只有一个或(x,y)->两个参数。 通常,不必定义参数的类型,因为Java 8可以从上下文中推断出它们。 在箭头运算符->之后,我们必须编写表达式,该表达式将成为我们声明的接口的返回值。
示例1.接收航班并返回价格的功能接口为:
x-> x.getPrice();
例子2.一个函数接口接收一个表示数字的String并返回一个带有相应值的Integer,将被写为:
x -> new Integer(x);
示例3.让我们再举一个接口Comparator的示例。 可以通过直接在调用代码上使用lambda表达式构造所需的Comparator来执行对Collections的sort方法的调用:
Collections.sort(flightList,(x,y)->x.getPrice().compareTo(y.getPrice()));
lambda表达式由其参数组成,在这种情况下为两个:括号之间的x和y,并用逗号分隔。 有两个参数,因为接口Comparator中的compare方法也需要两个参数。 正如我们可以看到的,即使我们不需要正式指定x和y都是对Flight类型的引用,因为Java 8编译器能够从上下文中“理解”它,因为既然我们要订购List <Flight> ,比较器必须为Flight类型,因此compare方法的参数也必须为该类型。 然后,在箭头符号“->”之后,编写表达式,compare方法应返回; 在我们的例子中,是int类型的表达式,其中包含航班价格之间的比较。
引用比较器的另一种方法是调用返回我们要比较的属性的方法。 例如,Java 8允许以下其他调用:
Collections.sort(flights,Comparator.comparing(Flight::getPrice));
在第二次调用时,Comparator接口调用静态方法compare,其参数是Function类型的功能接口,可以仅通过引用返回我们要比较的属性的方法来定义它。
Lambda表达式最直接在需要功能接口的方法调用时直接使用,但是如果某个Lambda表达式将要多次使用,则可以使用标识符进行声明。
例。 为了定义一个航班是否满载,我们将编写:
Predicate<Flight> flightFull = x->
x.getNumPassengers().equals(x.getNumSeats());
这样,标识符flightFull可以在所有具有Predicate类型参数的调用上替换Predicate接口。
如果功能接口需要输入的参数类型不同于为接口本身指定的类型,则更好的定义方法就好像它是方法一样。
例。 如果我们需要定义一个飞行谓词,以接收日期类型的参数,并告诉飞行是否在给定日期之后起飞,则我们定义:
Predicate<Flight> laterDate(Date f){
return x -> x.getDate().compareTo(f)>0;
}
4.谓词<T>
如前所述,谓词接口为需要某些过滤器或条件的方法实现了逻辑条件。 谓词实现了一种称为test的方法,该方法从类型T的对象返回布尔值。因此,谓词类型用于根据类型T的对象是否满足特定属性对其进行分类。 例如,给定一个Flight告诉它是否完成,给一个Book告诉它的标题是否包含某个特定单词,给一个Song告诉它是否持续超过x秒,或者给定一个String告诉它是否以某个字符开头。
例子1.判断航班是否满员的谓词是:
Predicate<Flight> flightFull = x->
x.getNumPassengers().equals(x.getNumSeats());
示例2.如果需要基于参数定义条件,则可以为功能接口提供输入参数。 例如,如果我们需要确定某个航班是否来自确定的日期,则可以定义:
Predicate<Flight> equalDate(Date f){
return x -> x.getDate().equals(f);
}
此外,还可以使用专用接口(例如DoublePredicate,IntPredicate和LongPredicate)从基本数据类型的对象获取逻辑值。
默认方法
谓词接口还具有实现逻辑操作的三种方法:negate()和(Predicate)和or(Predicate)。 例如,如果我们需要Predicate类型的参数来判断Flight是否对应于某个日期且已满,则将其写为:
equalDate(f).and(flightFull)
5. BiPredicate <T,U>
BiPredicate接口从两个不同类型的参数生成逻辑值。 例如,给定一个表示目的地和航班的字符串,它将返回该航班是否去往该目的地,给定一首歌曲和一段持续时间,它将判断歌曲的持续时间是否小于指定的持续时间,等等。
例。 如果某个航班在指定日期起飞,则返回的界面为:
BiPredicate<Flight, Date> getCoincidence = (x,y)->
y.equals(x.getFecha());
6.函数<T,R>
函数是具有apply方法的接口,该方法接收类型T的参数并返回类型R的对象。它主要用于从另一种派生或组合的类型转换对象; 例如,一本书的作者,一首歌的持续时间,一次航班的乘员人数等。Java 8提供了一组专用接口,这些接口的输入或输出参数类型不同。 例如,ToDoubleFunction <T>,ToIntFunction <T>,ToLongFunction <T>专门用于接收类型T的对象并返回在接口名称上指定的类型。 这些接口实现了一个名为applyAsX的方法,其中X将根据情况区分为Double,Int或Long。 相反,函数LongFunction <R>,IntFunction <R>和DoubleFunction <R>接收名称上指定的类型的值,并使用apply方法返回另一种类型R。 最后,还有六个名为XToYFunction的接口,其中X,Y取值Double,Int或Long,X为输入参数类型,Y为返回值类型。 他们实现的方法是ApplyAsY,其中Y是返回值类型。
示例1:给定飞行确定其持续时间的功能可以定义为:
Function<Flight, Duration> functionDuration = x->x.getDuration();
在这种情况下,如果Flight类型定义了getDuration方法,则可以在将使用Function类型作为输入参数的方法的调用上使用运算符:::
Flight::getDuration
当然,如果Function的表达式将不只使用一次,则lambda表达式x-> x.getDuration()可以作为需要此函数的方法的输入参数。
例子2.给定一个航班,返回其占用率的函数是:
Function<Flight,Double>functOccRatio=x-> 1.*x.getNumPasengers()/x.getNumSeats();
这种情况是专门功能的一个明显例子:
ToDoubleFunction<Flight> functOccRatio(){
return x->1.*x.getNumPassengers()/x.getNumSeats();
}
默认方法
Function接口有两种方法,可以让我们操作带有组合的函数:compose(Function)和andThen(Function)。 它们之间的区别在于所涉及功能的应用顺序。 应用方法f.compose(g)产生的函数首先应用g然后应用f,而f.andThen(g)是先应用f然后应用g的结果。
例。 让我们假设我们有一个函数,给定类型为Duration的对象,它将返回其转换为分钟:
Function<Duration,Integer> inMinutes=x->x.getMinutes()+x.getHours()*60;
另一个返回飞行时间的函数:
Function<Flight,Duration> getDuration = Flight::getDuration;
然后,以分钟为单位返回飞行时间的函数将是:
Function<Flight,Integer> getDurationInMinutes=inMinutes.compose(getDuration);
或者:
Function<Flight,Integer> getDurationInMinutes =getDuration.andThen(inMinutes);
7. BiFunction <T,U,R>
BiFunction是一个函数,该函数使用称为apply的方法接收类型T和U的两个参数并返回类型R的结果。 还存在三个专门用于返回某种类型的接口:ToDoubleBiFunction,ToIntBiFunction和ToLongBiFunction,它们实现了applyAsX方法,其中X可以是Double,Int或Long。
例。 要获得一个给定日期和航班的函数,该函数返回给定日期与航班起飞之间还剩下多少天,它是:
ToIntBiFunction<Flight, Date> getDays(Flight v, Date f){
return (x,y)->y.subtract(x.getDate());
}
8.消费者<T>
接口Consumer是Function的一个变体,其中不返回任何值,这意味着它使用称为accept的方法修改给定对象,该方法接收类型T的对象并返回void。 它们用于定义对对象的操作。 例如,将某个航班的价格增加一定的百分比,将“日期”减去几天,或者在控制台上打印一个值。 Java 8还提供了专门的接口DoubleConsumer,LongConsumer或IntConsumer,它们也实现了accept方法。
例子1.如果我们想将一个航班的价格提高10%,我们将定义一个消费者:
Consumer<Flight> incrementPrice10p = x->x.setPrice(x.getPrice()*1.1);
示例2.如果我们希望在作为参数传递的百分比上执行增量,则可以为Flight类型编写以下方法:
Consumer<Flight> incrementPrice(Double p){
return x->x.setPrice(x.getPrice()*(1+p/100.));
}
示例3。找到以下使用者来替换表达式System.out.println是很常见的:
Consumer<Flight> printFlight = x->System.out.println(x);
例子4.如果我们想有一个Flight方法,该方法可以根据条件对Flight类型的对象执行某种动作,我们可以这样写:
public void applyAction(Predicate<Flight> cond, Consumer<Flight> act){
if (cond.test(this)){
act.accept(this);
}
}
一旦我们有了一个类型为Flight的对象v,则调用前面的方法(如果乘客人数低于50)来提高v的价格将是:
v.applyAction(x->x.getNumPassengers()<50, x->x.incrementPrice(10.));
其中增量价格是示例2中定义的使用者。
9. BiConsumer <T,U>
BiConsumer是一个接口,用于定义对两个不同类型的输入参数的操作。 它用于表示修改接收其他类型对象的对象的操作。 它的专用接口是:ObjDoubleConsumer,ObjIntConsumer和ObjLongConsumer,它们接收类型T的对象和名称上指定的另一类型的对象。 它们都实现了一个称为accept的功能方法。
例。 要更改飞行时间,我们可以编写以下代码:
BiConsumer<Flight, Duration> changeDuration = (x,y)->x.setDuration(y);
10.供应商<T>
Supplier是一个接口,它使用称为get的方法提供T类型的对象而没有任何参数。 此外,还有专门的接口(例如BooleanSupplier,DoubleSupplier,IntSupplier和LongSupplier)提供指示类型的对象。 在这些情况下,他们实现的方法称为getAsX,其中X分别是Boolean,Double,Int或Long。
通常,类型为Supplier的接口只会调用构造函数。 这样,假设FlightImpl具有默认构造函数,则调用Flight构造函数的lambda表达式将是:
Supplier<Flight> giveMeFlight = ()-> new FlightImpl();
如果我们希望供应商有一个争论,我们将不得不写:
Supplier<Flight> giveMeFlight (String s) {
return ()->new FlightImpl(s);
}
建立供应商的另一种常用方法是使用方法表达式:
Supplier<Set<Integer>> giveMeSet = HashSet::new;
11. UnaryOperator <T>
UnaryOperator接口表示一个操作,该操作使用apply方法接收一个类型T的单个参数并返回另一个相同类型的对象。 这是Function接口的一种特殊情况,其输入和输出值的类型相同,Java将其实现为Function的子接口。 Java 8还具有专用接口DoubleUnaryOperator,IntUnaryOperator和LongUnaryOperator,它们分别实现方法applyAsX为X字符链Double,Int或Long。 由于此接口是Function的子接口,因此它也以相同的行为实现默认的方法compose和andThen。
例子1.如果我们需要一个操作员修改一个Duration,并加上一个参数给定的分钟数,我们可以这样写:
public UnaryOperator<Duration> addMinutes(Integer m){
return x -> x.sum(new DurationImpl(0,m));
}
12. BinaryOperator <T>
接口BinaryOperator表示一个操作,该操作接收两个T类型的操作数,并使用apply方法返回相同类型的结果。 如我们所见,这是BiFunction接口的一种特殊情况,其中三种类型T,U和R相同,Java 8将其实现为BiFunction的子接口。 还有一些专门技术,例如DoubleBinaryOperator,IntBinaryOperator和LongBinaryOperator可以操作数值。 在这些接口中,它们实现的方法是applyAsX ,其中X可以分别命名为Double,Int或Long。
示例1.我们定义了一个类型为Duration的类型,该类型存储一个Flight的持续时间,以小时和分钟为单位。 如果持续时间类型已经定义了sum方法:
public Duration sum(Duration d) {
Integer min = getMinutes() + d.getMinutes();
Integer hour = getHours() + d.getHours();
return new DurationImpl(hour+min/60,min%60);
}
然后我们可以将其重新定义为BinaryOperator:
BinaryOperator<Duration> addDur = (x,y) -> x.sum(y);
等效于其他表达式:
BinaryOperator<Duration> addDur = Duration::sum;
如果未为Duration定义方法sum,我们可以直接定义:
BinaryOperator<Duration> addDur = (x,y)-> {
Integer min = x.getMinutes() + y.getMinutes();
Integer hour = x.getHours() + y.getHours();
return new DurationImpl(hour+min/60,min%60);
};
示例2. DoubleBinaryOperator接口允许我们将实函数定义为其他两个函数的组合。 例如,如果我们想将函数h定义为其他两个未知函数f和g的商,我们将编写代码:
public DoubleBinaryOperator functionH(DoubleBinaryOperator f,
DoubleBinaryOperator g){
return (x,y)->f.applyAsDouble(x,y)/g.applyAsDouble(x,y);
}
这样,两个数字的加法与乘积之间的商的可能调用为:
public Double callFunctionH(Double x, Double y){
return functionH((a,b)->a+b,(a,b)->a*b).applyAsDouble(x,y);
}
翻译自: https://www.javacodegeeks.com/2015/03/functional-interfaces.html
sap界面功能