标签: java-8

Java8:lambdas和重载方法的歧义

我正在玩java8 lambdas,我遇到了编译器错误,我没想到.

假设我有一个函数interface A,一个abstract class B和一个class C重载方法,它们可以采用AB作为参数:

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)

java generics lambda java-8

38
推荐指数
2
解决办法
7963
查看次数

为什么Java 8的Predicate <T>不扩展Function <T,Boolean>

如果我编写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专家组邮件列表进行了更改.

java lambda functional-programming predicate java-8

38
推荐指数
4
解决办法
4830
查看次数

为什么此类型推断不适用于此Lambda表达式方案?

我有一个奇怪的场景,类型推断不起作用,因为我期望使用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以使其按预期工作?

java lambda type-inference java-8

38
推荐指数
2
解决办法
6697
查看次数

Java 8 Lambda - 两个列表的交集

我试图找到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并做一些事情.

java lambda intersection java-8

38
推荐指数
2
解决办法
7万
查看次数

为什么 javac 为最终字段插入 Objects.requireNonNull(this) ?

考虑以下类:

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)

java javac java-8 ecj java-11

38
推荐指数
1
解决办法
970
查看次数

在Java 8/jsr310中格式化持续时间

我正在将项目从Joda-Time过渡到java8的本地时间库,我遇到了麻烦.我一直无法找到持续时间的格式化程序.我想有一个自定义字符串格式,例如,HHH + MM,其中75小时和15分钟的持续时间格式为"75 + 15".通过转换为句点并使用PeriodFormatter,使用Joda-Time很容易,但我无法在Java8中找到这种类型的类.我错过了什么吗?

java duration jodatime java-8 java-time

37
推荐指数
4
解决办法
3万
查看次数

使用Java 8 Stream API查找枚举值

假设有一个名为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 …

java enums functional-programming java-8 java-stream

37
推荐指数
3
解决办法
5万
查看次数

在Java 8中,是否有ByteStream类?

Java的8提供Stream<T>专业化的double,intlong:DoubleStream,IntStreamLongStream分别.但是,我byte文档中找不到相应的内容.

Java 8是否提供了一个ByteStream类?

java byte boxing java-8 java-stream

37
推荐指数
2
解决办法
2万
查看次数

杰克逊将日期时间的ISO8601反序列化为Java8 Instant

我正在尝试使用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?

java datetime json jackson java-8

37
推荐指数
4
解决办法
4万
查看次数

为什么必须用lambda体中的完整代码块来包含throw语句?

如果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)

java lambda exception java-8

37
推荐指数
3
解决办法
793
查看次数