我正在玩java8 lambdas,我遇到了编译器错误,我没想到.
假设我有一个函数interface A,一个abstract class B和一个class C重载方法,它们可以采用A或B作为参数:
public interface A {
void invoke(String arg);
}
public abstract class B {
public abstract void invoke(String arg);
}
public class C {
public void apply(A x) { }
public B apply(B x) { return x; }
}
Run Code Online (Sandbox Code Playgroud)
然后我可以传入一个lambda c.apply,它正确地解决了c.apply(A).
C c = new C();
c.apply(x -> System.out.println(x));
Run Code Online (Sandbox Code Playgroud)
但是当我更改B作为泛型版本的参数的重载时,编译器报告两个重载是不明确的.
public class C {
public void apply(A x) { …Run Code Online (Sandbox Code Playgroud) 如果我编写Predicate接口,我想在接口中编码它只是一个返回原始布尔值的函数,如下所示:
@FunctionalInterface
public interface Predicate<T> extends Function<T, Boolean> {
boolean test(T t);
@Override
default Boolean apply(T t) {
return Boolean.valueOf(test(t));
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道,有没有令人信服的理由让Java 8 API设计者选择将Predicate与Function完全分开?是否有一些证据表明他们认为这样做并决定反对呢?我想类似的问题适用于所有其他'特殊'功能接口,如Consumer(可能是Function <T,Void>),Supplier(Function <Void,T>)和原始函数,如IntFunction(Function <Integer,T>).
我没有深入和彻底地考虑过这个问题的所有后果,所以我可能会遗漏一些东西.
编辑:一些答案强调了应用和测试之间的语义区别.我不是说我不欣赏这种区别,我同意这种区别是有益的.我不明白的是,为什么Predicate不是一个函数,就像List是一个Collection或Double是一个Number,它是一个Object.
如果Predicate(以及所有其他特殊的通用功能接口,例如Consumer,Supplier,IntUnaryOperator等)与Function有这种关系,它将允许人们在预期使用Function参数的地方使用它(想到的是组合与其他功能,例如,呼叫myFunction.compose(比如说myPredicate)或避免在API中写入几个专门的功能时,如上所述的这种汽车(未)拳击实施将是足够的)
编辑2:看看openjdk lambda项目,我发现原始的功能接口用于扩展功能,直到2012-12-19的Brian Goetz提交.我找不到具体的原因,在那个时候对任何lambda-dev或JSR专家组邮件列表进行了更改.
我有一个奇怪的场景,类型推断不起作用,因为我期望使用lambda表达式.这是我真实场景的近似值:
static class Value<T> {
}
@FunctionalInterface
interface Bar<T> {
T apply(Value<T> value); // Change here resolves error
}
static class Foo {
public static <T> T foo(Bar<T> callback) {
}
}
void test() {
Foo.foo(value -> true).booleanValue(); // Compile error here
}
Run Code Online (Sandbox Code Playgroud)
我在倒数第二行得到的编译错误是
对于Object类型,方法booleanValue()未定义
如果我将lambda转换为Bar<Boolean>:
Foo.foo((Bar<Boolean>)value -> true).booleanValue();
Run Code Online (Sandbox Code Playgroud)
或者如果我更改方法签名Bar.apply以使用原始类型:
T apply(Value value);
Run Code Online (Sandbox Code Playgroud)
然后问题就消失了.我期望它的工作方式是:
Foo.foo call应该推断出一个返回类型 boolean value在lambda中应该推断出来Value<Boolean>.为什么这个推理不能按预期工作?如何更改此API以使其按预期工作?
我试图找到intersection两个基于某些条件并执行一些步骤的列表.找不到办法(在学习阶段):)
Double totalAmount = 0.00d;
Double discount = 0.00d;
List<OrderLineEntry> orderLineEntryList = orderEntry.getOrderReleases().stream()
.flatMap(orderReleaseEntry -> orderReleaseEntry.getOrderLines().stream())
.filter(orderLineEntry -> orderLineEntry.getStatus().equals("PP") || orderLineEntry.getStatus().equals("PD"))
.collect(Collectors.toList());
for (OrderLineEntry orderLineEntry : orderLineEntryList) {
for (SplitLineEntry splitLineEntry : splitReleaseEntry.getLineEntries()) {
if (splitLineEntry.getOrderLineId().equals(orderLineEntry.getId()) && splitLineEntry.getStatusCode() != "PX") {
totalAmount += orderLineEntry.getFinalAmount();
couponDiscount += orderLineEntry.getCouponDiscount() == null ? 0.00d : orderLineEntry.getCouponDiscount();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,逻辑很简单
根据一些过滤器从订单获取所有项目list并与另一个过滤list并做一些事情.
考虑以下类:
class Temp {
private final int field = 5;
int sum() {
return 1 + this.field;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我编译和反编译这个类:
> javac --version
javac 11.0.5
> javac Temp.java
> javap -v Temp.class
...
int sum();
descriptor: ()I
flags: (0x0000)
Code:
stack=2, locals=1, args_size=1
0: iconst_1
1: aload_0
2: invokestatic #3 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
5: pop
6: iconst_5
7: iadd
8: ireturn
Run Code Online (Sandbox Code Playgroud)
简单来说,javac编译sum()成这样:
int sum() {
final int n = 1;
Objects.requireNonNull(this); // <---
return n + …Run Code Online (Sandbox Code Playgroud) 我正在将项目从Joda-Time过渡到java8的本地时间库,我遇到了麻烦.我一直无法找到持续时间的格式化程序.我想有一个自定义字符串格式,例如,HHH + MM,其中75小时和15分钟的持续时间格式为"75 + 15".通过转换为句点并使用PeriodFormatter,使用Joda-Time很容易,但我无法在Java8中找到这种类型的类.我错过了什么吗?
假设有一个名为Type的简单枚举,如下所示:
enum Type{
X("S1"),
Y("S2");
private String s;
private Type(String s) {
this.s = s;
}
}
Run Code Online (Sandbox Code Playgroud)
s使用for-loop的静态方法(假设该方法在enum中定义)可以轻松地找到给定的正确枚举,例如:
private static Type find(String val) {
for (Type e : Type.values()) {
if (e.s.equals(val))
return e;
}
throw new IllegalStateException(String.format("Unsupported type %s.", val));
}
Run Code Online (Sandbox Code Playgroud)
我认为使用Stream API表达的功能等价物将是这样的:
private static Type find(String val) {
return Arrays.stream(Type.values())
.filter(e -> e.s.equals(val))
.reduce((t1, t2) -> t1)
.orElseThrow(() -> {throw new IllegalStateException(String.format("Unsupported type %s.", val));});
}
Run Code Online (Sandbox Code Playgroud)
我们怎么能写得更好更简单?这段代码感觉很强烈,不太清楚.该reduce()特别是似乎笨重和滥用,因为它没有任何积累,不进行计算,并始终直接返回t1(所提供的过滤器返回一个值-如果没有这显然是一个灾难),更何况t2是有多余的混乱.然而,我在Stream API中找不到任何东西,只是以某种方式T从a 直接返回a …
我正在尝试使用Jackson将ISO8601格式的日期反序列化为Java8 Instant.我使用ObjectMapper注册了JavaTimeModule,关闭了WRITE_DATES_AS_TIMESTAMPS.
但是,如果尝试反序列化2016-03-28T19:00:00.000 + 01:00它将无法工作,因为似乎JavaTimeModule将仅反序列化使用UTC时区偏移量格式化的日期时间(例如2016-03-28T18:00 :00.000Z).然后我尝试使用@JsonFormat注释,如下所示:
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "UTC")
Run Code Online (Sandbox Code Playgroud)
像这样:
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = JsonFormat.DEFAULT_TIMEZONE)
Run Code Online (Sandbox Code Playgroud)
但是,这些都不起作用,我得到一个例外:
com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra (through reference chain: org.example.Article["date"])
Run Code Online (Sandbox Code Playgroud)
这意味着时区参数被忽略,日期时间格式化程序不知道如何在没有时区的情况下格式化Instant.
有没有办法在没有编写自定义反序列化器的情况下,使用Jackson和JavaTimeModule将不在UTC时区偏移的ISO8601字符串反序列化为Java 8 Instant?
如果lambda函数中有一个语句,我们可以省略为它定义完整的代码块:
new Thread(() -> System.out.println());
Run Code Online (Sandbox Code Playgroud)
为什么抛出异常的语句不是这种情况?这会产生一个编译错误,说明'{' expected:
new Thread(() -> throw new RuntimeException());
Run Code Online (Sandbox Code Playgroud)
当然,将lambda主体封装在代码块中可以:
new Thread(() -> {
throw new RuntimeException();
});
Run Code Online (Sandbox Code Playgroud)