我刚刚在我们的生产环境中遇到了相当不愉快的经历 OutOfMemoryErrors: heapspace..
我将这个问题追溯到我ArrayList::new
在函数中的使用.
要通过声明的构造函数(t -> new ArrayList<>()
)验证这实际上比正常创建更糟糕,我编写了以下小方法:
public class TestMain {
public static void main(String[] args) {
boolean newMethod = false;
Map<Integer,List<Integer>> map = new HashMap<>();
int index = 0;
while(true){
if (newMethod) {
map.computeIfAbsent(index, ArrayList::new).add(index);
} else {
map.computeIfAbsent(index, i->new ArrayList<>()).add(index);
}
if (index++ % 100 == 0) {
System.out.println("Reached index "+index);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行方法newMethod=true;
将导致方法OutOfMemoryError
在索引达到30k后失败.随着newMethod=false;
程序不会失败,但一直冲击直到被杀(索引容易达到150万).
为什么在堆上ArrayList::new
创建如此多的Object[]
元素会导致OutOfMemoryError
如此之快?
(顺便说一下 - 当集合类型出现时也会发生HashSet …
我有一个包含一些User对象的列表,我正在尝试对列表进行排序,但只能使用方法引用,使用lambda表达式,编译器会给出错误:
List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error
Run Code Online (Sandbox Code Playgroud)
错误:
com\java8\collectionapi\CollectionTest.java:35: error: cannot find symbol
userList.sort(Comparator.comparing(u -> u.getName()).reversed());
^
symbol: method getName()
location: variable u of type Object
1 error
Run Code Online (Sandbox Code Playgroud) 考虑我有以下代码:
class Foo {
Y func(X x) {...}
void doSomethingWithAFunc(Function<X,Y> f){...}
void hotFunction(){
doSomethingWithAFunc(this::func);
}
}
Run Code Online (Sandbox Code Playgroud)
假设hotFunction
经常被调用.那么缓存是否可取this::func
,也许是这样的:
class Foo {
Function<X,Y> f = this::func;
...
void hotFunction(){
doSomethingWithAFunc(f);
}
}
Run Code Online (Sandbox Code Playgroud)
就我对java方法引用的理解而言,虚拟机在使用方法引用时会创建匿名类的对象.因此,缓存引用将仅创建该对象一次,而第一种方法在每个函数调用上创建它.它是否正确?
是否应缓存出现在代码中热位置的方法引用,或者VM是否能够对此进行优化并使缓存变得多余?是否存在关于此的一般最佳实践,或者这种高度VM实现是否特定于此类缓存是否有用?
目前正在进入Java 8 lambda表达式和方法引用.
我想传递一个没有args且没有返回值的方法作为另一个方法的参数.这就是我这样做的方式:
public void one() {
System.out.println("one()");
}
public void pass() {
run(this::one);
}
public void run(final Function function) {
function.call();
}
@FunctionalInterface
interface Function {
void call();
}
Run Code Online (Sandbox Code Playgroud)
我知道有一组预定义功能接口在java.util.function
诸如Function<T,R>
,但我没有找到一个不带任何参数,而不是产生结果.
假设我们有一个IntFunction
返回整数数组的变量:
IntFunction<int[]> i;
Run Code Online (Sandbox Code Playgroud)
使用Java 8泛型,可以使用如下构造函数引用初始化此变量:
i = int[]::new
Run Code Online (Sandbox Code Playgroud)
Java编译器如何将其转换为字节码?
我知道对于其他类型,例如String::new
,它可以使用invokedynamic
指向String构造函数的指令java/lang/String.<init>(...)
,这只是一个具有特殊含义的方法.
这对数组有什么用处,看到有构造数组的特殊指令?
我注意到使用Java 8方法引用的未处理异常有些奇怪.这是我的代码,使用lambda表达式() -> s.toLowerCase()
:
public class Test {
public static void main(String[] args) {
testNPE(null);
}
private static void testNPE(String s) {
Thread t = new Thread(() -> s.toLowerCase());
// Thread t = new Thread(s::toLowerCase);
t.setUncaughtExceptionHandler((t1, e) -> System.out.println("Exception!"));
t.start();
}
}
Run Code Online (Sandbox Code Playgroud)
它打印"Exception",所以它工作正常.但是当我Thread t
改为使用方法引用时(甚至IntelliJ建议):
Thread t = new Thread(s::toLowerCase);
Run Code Online (Sandbox Code Playgroud)
异常没有被捕获:
Exception in thread "main" java.lang.NullPointerException
at Test.testNPE(Test.java:9)
at Test.main(Test.java:4)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Run Code Online (Sandbox Code Playgroud)
有人能解释一下这里发生了什么吗?
使用以下结构是否存在差异,除了后者的可读性稍好一些?
someList.stream().map(item -> new NewClass(item)).collect(Collectors.toList());
someList.stream().map(NewClass::new).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud) 使用的方法引用具有返回类型Integer
。但是String
在下面的示例中,允许不兼容。
如何解决方法with
声明以确保方法引用类型安全而无需手动强制转换?
import java.util.function.Function;
public class MinimalExample {
static public class Builder<T> {
final Class<T> clazz;
Builder(Class<T> clazz) {
this.clazz = clazz;
}
static <T> Builder<T> of(Class<T> clazz) {
return new Builder<T>(clazz);
}
<R> Builder<T> with(Function<T, R> getter, R returnValue) {
return null; //TODO
}
}
static public interface MyInterface {
Integer getLength();
}
public static void main(String[] args) {
// missing compiletimecheck is inaceptable:
Builder.of(MyInterface.class).with(MyInterface::getLength, "I am NOT an Integer");
// compile time …
Run Code Online (Sandbox Code Playgroud) 我刚开始学习Java流并遇到了问题.请看下面的例子.这是Node类的一部分:
private Map<String, Node> nodes;
public Optional<Node> child(String name) {
return Optional.<Node>ofNullable(nodes.get(name));
}
private void findChildren(String name, List<Node> result) {
child(name).ifPresent(result::add);
nodes.values().stream()
// .map(Node::findChildren(name, result))
// .forEach(Node::findChildren(name, result))
.forEach(node -> node.findChildren(name, result));
}
Run Code Online (Sandbox Code Playgroud)
我的目的是使用流中每个节点上的名称和结果参数调用#findChildren.我试图使用方法引用Node :: findChildren没有运气.我很欣赏其他与->
运营商合作的解决方案.
是否有可能将方法引用与参数一起使用?我喜欢流的想法,我只想让代码更具可读性.
实际上,我认为有一个类似的问题方法引用与我读过的参数,但无法弄清楚如何在我的代码中使用bind2方法.这是唯一的解决方案吗?
java lambda java-stream functional-interface method-reference
Java8中是否有一种方法可以使用方法引用作为Function
对象来使用其方法,例如:
Stream.of("ciao", "hola", "hello")
.map(String::length.andThen(n -> n * 2))
Run Code Online (Sandbox Code Playgroud)
这个问题与之无关Stream
,它只是作为例子使用,我想对方法参考有答案
java ×10
method-reference ×10
java-8 ×8
lambda ×7
java-stream ×2
arrays ×1
caching ×1
constructor ×1
generics ×1