小编Bri*_*etz的帖子

Java 11 - 针对Java 8的性能回归?

更新:看到每个方法可能会遇到不同的性能问题,我决定将这个问题分成两个:

  1. Java 11中的空方法明显慢于Java 8
  2. 在Java 11中使用堆栈跟踪的速度明显慢于Java 8

最初的讨论可以在下面找到......


当我遇到一些令人惊讶的数据时,我正在比较我的库在Java 8和11下的性能.这是基准代码:

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.infra.Blackhole;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark
{
    @Benchmark
    public void emptyMethod()
    {
    }

    @Benchmark
    public void throwAndConsumeStacktrace(Blackhole bh)
    {
        try
        {
            throw new IllegalArgumentException("I love benchmarks");
        }
        catch (IllegalArgumentException e)
        {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            bh.consume(sw.toString());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

运行jmh 1.21,OracleJDK 1.8.0_192返回:

MyBenchmark.emptyMethod                avgt   25      0.363 ±   0.001  ns/op
MyBenchmark.throwAndConsumeStacktrace  avgt …
Run Code Online (Sandbox Code Playgroud)

performance microbenchmark java-8 jmh java-11

54
推荐指数
0
解决办法
3695
查看次数

Java8流顺序和并行执行产生不同的结果?

在Java8中运行以下流示例:

    System.out.println(Stream
        .of("a", "b", "c", "d", "e", "f")
        .reduce("", (s1, s2) -> s1 + "/" + s2)
    );
Run Code Online (Sandbox Code Playgroud)

收益率:

/a/b/c/d/e/f
Run Code Online (Sandbox Code Playgroud)

这是 - 当然 - 毫不奇怪.由于http://docs.oracle.com/javase/8/docs/api/index.html?overview-summary.html,流顺序执行还是并行执行无关紧要:

除了标识为显式非确定性的操作(例如findAny())之外,流是顺序执行还是并行执行不应更改计算结果.

AFAIK reduce()是确定性的并且(s1, s2) -> s1 + "/" + s2是关联的,因此添加parallel()应该产生相同的结果:

    System.out.println(Stream
            .of("a", "b", "c", "d", "e", "f")
            .parallel()
            .reduce("", (s1, s2) -> s1 + "/" + s2)
    );
Run Code Online (Sandbox Code Playgroud)

但是我机器上的结果是:

/a//b//c//d//e//f
Run Code Online (Sandbox Code Playgroud)

这有什么不对?

BTW:使用(首选).collect(Collectors.joining("/"))而不是为顺序和并行执行reduce(...)产生相同的结果a/b/c/d/e/f.

JVM详细信息:

java.specification.version: 1.8
java.version: 1.8.0_31
java.vm.version: 25.31-b07
java.runtime.version: 1.8.0_31-b13
Run Code Online (Sandbox Code Playgroud)

java lambda java-8 java-stream

48
推荐指数
2
解决办法
3030
查看次数

为什么Java 8类型推断不考虑Lambdas在重载选择中引发的异常?

关于lambdas及其相关的异常签名,我有一个关于Java 8推断的问题.

如果我定义一些方法foo:

public static <T> void foo(Supplier<T> supplier) {
    //some logic
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后,我得到了foo(() -> getTheT());在大多数情况下能够为给定的内容编写的漂亮而简洁的语义T.但是,在此示例中,如果我的getTheT操作声明了它throws Exception,我的foo方法使得供应商不再编译:供应商方法签名get不会抛出异常.

这似乎是解决这个问题的一个不错的方法是重载foo以接受任一选项,重载定义为:

public static <T> void foo(ThrowingSupplier<T> supplier) {
   //same logic as other one
   ...
}
Run Code Online (Sandbox Code Playgroud)

其中ThrowingSupplier定义为

public interface ThrowingSupplier<T> {
   public T get() throws Exception;
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我们有一个引发异常的供应商类型和一个不引发异常的供应商类型.所需的语法将是这样的:

foo(() -> operationWhichDoesntThrow()); //Doesn't throw, handled by Supplier
foo(() -> operationWhichThrows()); //Does throw, handled by ThrowingSupplier
Run Code Online (Sandbox Code Playgroud)

但是,这会导致问题,因为lambda类型不明确(可能无法在Supplier和ThrowingSupplier之间解决).做一个明确的演员foo((ThrowingSupplier)(() -> operationWhichThrows()));可以工作,但它摆脱了所需语法的大部分简洁性.

我想基本的问题是:如果Java编译器能够解决我的一个lambdas由于它在仅供应商案例中抛出异常而不兼容的事实,为什么它不能使用相同的信息来导出二级,类型推理案例中lambda的类型?

任何人都可以指出的任何信息或资源同样值得赞赏,因为我不太确定在哪里可以找到有关此事的更多信息. …

java lambda type-inference exception java-8

40
推荐指数
2
解决办法
1470
查看次数

为什么Stream没有toList()方法?

使用Java 8流时,采用列表,从中创建流,执行业务并将其转换回来是很常见的.就像是:

 Stream.of(-2,1,2,-5)
        .filter(n -> n > 0)
        .map(n -> n * n)
        .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

为什么' .collect(Collectors.toList())'部分没有捷径/方便的方法?在Stream接口上,有将方法转换为数组的方法toArray(),为什么toList()缺少?

恕我直言,将结果转换为列表比数组更常见.我可以忍受这一点,但称这种丑陋是令人讨厌的.

有任何想法吗?

java java-8 java-stream

34
推荐指数
3
解决办法
4114
查看次数

用非密封类扩展密封类有什么意义?

我真的不明白为什么non-sealedJEP 360/Java 15 中有一个关键字。对我来说,密封类的扩展应该只是 final 或密封类本身。

提供“非密封”关键字将邀请开发人员进行黑客攻击。为什么我们允许将密封类扩展为非密封类?

java sealed-class java-15 java-sealed-type

25
推荐指数
2
解决办法
1793
查看次数

局部变量的Java 10类型推断可以推断出无效吗?

使用Java 10,我们可以使用类型推断.

String s1 = "hello"; // before Java 10
var s2 = "hello"; // now
Run Code Online (Sandbox Code Playgroud)

但是,有一件事我们以前做不到:有类型为void的变量.

因此,在以前的版本中,我们根本无法定义变量类型void.但是现在我们可以将方法的结果分配给void变量:

void emptyMethod() { }
...

void v1 = emptyMethod(); // won't compile
var v2 = emptyMethod(); // no problem at all
Run Code Online (Sandbox Code Playgroud)

问题是 - 它为什么甚至编译,它的目的是什么?你有这个奇怪的用例吗?

类型变量void没有方法,甚至不能用作方法的参数.

java type-inference java-10

19
推荐指数
1
解决办法
1260
查看次数

在 Java 17 中使用 Javascript 脚本引擎

我必须将项目从 Java 8 迁移到 Java 17。

我可以解决大多数问题,但它包含一个方法,在该方法中我使用 ScriptEngineManager 来评估数学术语。

 ScriptEngineManager mgr = new ScriptEngineManager();
 ScriptEngine e = mgr.getEngineByName("JavaScript");
 
 String t = "5*7";
 if (isMathTerm(t)) {
    System.out.println(e.eval(t).toString());
 }
Run Code Online (Sandbox Code Playgroud)

在 Java 8 中它按要求工作,但在 Java 17 中e始终为 null。

据谷歌称,Java 17 不再支持 JavaScript 引擎。

由于项目限制,我不允许使用第三方库。

Java 17 中有没有正确的方法来处理这个问题?

java eval scriptengine java-17

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

通过Java 8中的方法引用调用toString

我错过了什么?为什么我必须在Object::toString下面使用而不是Integer::toString?它与带有泛型的类型擦除有什么关系吗?

Arrays.asList(1,2,3).stream().map(Integer::toString).forEach(System.out::println); //Won't compile

Arrays.asList(1,2,3).stream().map(Object::toString).forEach(System.out::println); //Compiles and runs fine
Run Code Online (Sandbox Code Playgroud)

java java-8 method-reference

9
推荐指数
1
解决办法
4442
查看次数

Java 8 Lambda分组同时使用X和Y.

我正在寻找一个lambda来优化已检索的数据.我有一个原始结果集,如果用户没有更改我希望使用java的lambda按结果分组的日期.而且我是java的新手lambdas.

我正在寻找的lambda与这个查询相似.

select z, w, min(x), max(x), avg(x), min(y), max(y), avg(y) from table group by x, w;
Run Code Online (Sandbox Code Playgroud)

java lambda java-8

8
推荐指数
1
解决办法
2806
查看次数

文本块内的 Java 正则表达式

我当然希望这能得到支持:

\n
private static void regex() {\n    String plain = "\\\\w+";\n    String withTextBlocks = """\n        \\w+\n    """;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

withTextBlocks不能在 Java-17 下编译。\xe2\x80\x99 是不是我们不应该转义的文本块点?我已经通过了JEP,也许解释就在那里,但我无法理解它。第二个问题,如果有人知道的话,未来是否有一个 JEP?谢谢。

\n

java regex escaping java-17

7
推荐指数
1
解决办法
564
查看次数