更新:看到每个方法可能会遇到不同的性能问题,我决定将这个问题分成两个:
最初的讨论可以在下面找到......
当我遇到一些令人惊讶的数据时,我正在比较我的库在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) 在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) 关于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 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()
缺少?
恕我直言,将结果转换为列表比数组更常见.我可以忍受这一点,但称这种丑陋是令人讨厌的.
有任何想法吗?
我真的不明白为什么non-sealed
JEP 360/Java 15 中有一个关键字。对我来说,密封类的扩展应该只是 final 或密封类本身。
提供“非密封”关键字将邀请开发人员进行黑客攻击。为什么我们允许将密封类扩展为非密封类?
使用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 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 中有没有正确的方法来处理这个问题?
我错过了什么?为什么我必须在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) 我正在寻找一个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) 我当然希望这能得到支持:
\nprivate 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?谢谢。
java ×9
java-8 ×6
lambda ×3
java-17 ×2
java-stream ×2
escaping ×1
eval ×1
exception ×1
java-10 ×1
java-11 ×1
java-15 ×1
jmh ×1
performance ×1
regex ×1
scriptengine ×1
sealed-class ×1