在Java 8中有"方法参考"功能.其中一种是"引用特定类型的任意对象的实例方法"
http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html#type
有人可以解释"特定类型的任意对象"在这种情况下的含义吗?
这与这个问题有关:如何进行功能组合?
我注意到方法引用可以分配给声明为的变量Function,因此我假设它应该具有andThen或compose函数,因此我希望我们可以直接组合它们.但很显然,我们需要把它们分配给声明为可变的Function第一(或类型转换调用之前)之前,我们可以称之为andThen或compose他们.
我怀疑我可能会对这应该如何运作有一些误解.
所以我的问题:
andThen方法之前,为什么我们需要先键入或将其分配给变量?示例代码如下.
public class MyMethods{
public static Integer triple(Integer a){return 3*a;}
public static Integer quadruple(Integer a){return 4*a;}
public int operate(int num, Function<Integer, Integer> f){
return f.apply(num);
}
public static void main(String[] args){
MyMethods methods = new MyMethods();
int three = methods.operate(1, MyMethods::triple); // This is fine
// Error below
// int twelve = methods.operate(1, (MyMethods::triple).andThen(MyMethods::quadruple));
// But this one is …Run Code Online (Sandbox Code Playgroud) 假设有一个典型的Java Bean:
class MyBean {
void setA(String id) {
}
void setB(String id) {
}
List<String> getList() {
}
}
Run Code Online (Sandbox Code Playgroud)
我想在BiConsumer的帮助下创建一种更抽象的方式来调用setter:
Map<SomeEnum, BiConsumer<MyBean, String>> map = ...
map.put(SomeEnum.A, MyBean::setA);
map.put(SomeEnum.B, MyBean::setB);
map.put(SomeEnum.List, (myBean, id) -> myBean.getList().add(id));
Run Code Online (Sandbox Code Playgroud)
有没有一种方法,以取代拉姆达(myBean, id) -> myBean.getList().add(id)与链接的方法引用,类似(myBean.getList())::add或者myBean::getList::add还是其他什么东西?
我遇到了奇怪的错误消息,我认为这可能是不正确的。考虑以下代码:
public class Overloaded {
public interface Supplier {
int get();
}
public interface Processor {
String process(String s);
}
public static void load(Supplier s) {}
public static void load(Processor p) {}
public static int genuinelyAmbiguous() { return 4; }
public static String genuinelyAmbiguous(String s) { return "string"; }
public static int notAmbiguous() { return 4; }
public static String notAmbiguous(int x, int y) { return "string"; }
public static int strangelyAmbiguous() { return 4; }
public static String strangelyAmbiguous(int …Run Code Online (Sandbox Code Playgroud) java overloading arity functional-interface method-reference
考虑以下课程:
import java.util.Objects;
import java.util.function.Predicate;
public class LambdaVsMethodRef {
public static void main(String[] args) {
Predicate<Object> a = Objects::nonNull;
Predicate<Object> b = x -> x != null;
}
}
Run Code Online (Sandbox Code Playgroud)
第一个谓词是从方法引用创建的,另一个是lambda表达式.这些谓词具有相同的行为(nonNull正文是正确的return obj != null;).lambda缩短了两个字符(可能允许流管道适合一行).
除了代码风格,和之间有什么区别?换句话说,我应该更喜欢一个吗?Objects::nonNullx -> x != null
拉姆达-dev的和λ-库-规格- {观察员,专家}邮件列表邮件提isNull,nonNull以及isNotNull(初名)并没有解决这个问题.(我很惊讶没有人质疑添加Objects方法,因为它们可以用lambda轻松替换,但另一方面,也是如此Integer::sum.)
我也查看了字节码javap.唯一的区别是传递给lambda metafactory bootstrap方法的方法句柄:
BootstrapMethods:
0: #16 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#17 (Ljava/lang/Object;)Z
#18 invokestatic java/util/Objects.nonNull:(Ljava/lang/Object;)Z
#17 (Ljava/lang/Object;)Z
1: #16 invokestatic …Run Code Online (Sandbox Code Playgroud) 为什么这不起作用?我得到编译错误"无法对非静态方法打印静态引用..."
public class Chapter3 {
public void print(String s) {
System.out.println(s);
}
public static void main(String[] args) {
Arrays.asList("a", "b", "c").forEach(Chapter3::print);
}
}
Run Code Online (Sandbox Code Playgroud) 我想知道方法引用和功能接口的所有这些东西如何在较低级别上工作.最简单的例子是我们有一些List
List<String> list = new ArrayList<>();
list.add("b");
list.add("a");
list.add("c"):
Run Code Online (Sandbox Code Playgroud)
现在我们想用Collections类对它进行排序,所以我们可以调用:
Collections.sort(list, String::compareToIgnoreCase);
Run Code Online (Sandbox Code Playgroud)
但是,如果我们定义自定义比较器,它可能是这样的:
Comparator<String> customComp = new MyCustomOrderComparator<>();
Collections.sort(list, customComp::compare);
Run Code Online (Sandbox Code Playgroud)
问题是Collections.sort有两个参数:List和Comparator.由于Comparator是功能接口,因此可以使用具有相同签名(参数和返回类型)的lambda表达式或方法引用替换它.那么它是如何工作的,我们也可以传递compareTo只引用一个参数并且这些方法的签名不匹配?如何在Java8中翻译方法引用?
我正在深入探讨 Java 8 Lambda和方法参考等功能.玩了一下让我看到以下示例:
public class ConsumerTest {
private static final String[] NAMES = {"Tony", "Bruce", "Steve", "Thor"};
public static void main(String[] args) {
Arrays.asList(NAMES).forEach(Objects::requireNonNull);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
为什么main方法中的行会编译?
如果我理解正确的话,引用的方法的签名必须对应于功能接口的SAM签名.在这种情况下,消费者需要以下签名:
void accept(T t);
Run Code Online (Sandbox Code Playgroud)
但是,该requireNonNull方法返回T而不是void:
public static <T> T requireNonNull(T obj)
Run Code Online (Sandbox Code Playgroud) 声纳告诉我"用方法参考替换这个lambda"
public class MyClass {
private List<SomeValue> createSomeValues(List<Anything> anyList) {
return anyList //
.stream() //
.map(anything -> createSomeValue(anything)) //
.collect(Collectors.toList());
}
private SomeValue createSomeValue(Anything anything) {
StatusId statusId = statusId.fromId(anything.getStatus().getStatusId());
return new SomeValue(anything.getExternId(), statusId);
}
}
Run Code Online (Sandbox Code Playgroud)
这可能吗?我尝试了几件事,比如
.map(MyClass::createSomeValue) //
Run Code Online (Sandbox Code Playgroud)
但我需要将方法更改为静态.而且我不是静态方法的忠实粉丝.
SonarQube的解释是:
方法/构造函数引用比使用lambdas更紧凑和可读,因此是首选.
当我运行此代码时
List<int[]> list = Arrays.asList(new int[]{1, 2, 3}, new int[]{4, 5});
int[][] arr = list.stream().map(j -> j.clone()).toArray(int[][]::new);
System.out.println(Arrays.deepToString(arr));
Run Code Online (Sandbox Code Playgroud)
它按预期工作,我得到输出
[[1, 2, 3], [4, 5]]
Run Code Online (Sandbox Code Playgroud)
但是,如果我用方法引用替换lambda clone()
int[][] arr = list.stream().map(int[]::clone).toArray(int[][]::new);
Run Code Online (Sandbox Code Playgroud)
我得到一个运行时异常:
Exception in thread "main" java.lang.NoClassDefFoundError: Array
at Main.lambda$MR$main$clone$8ed4b78b$1(Main.java:14)
at Main$$Lambda$1/1160460865.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:576)
at java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:255)
at java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:438)
at Main.main(Main.java:14)
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:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ClassNotFoundException: Array
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method) …Run Code Online (Sandbox Code Playgroud) java ×10
method-reference ×10
java-8 ×9
lambda ×3
arity ×1
eclipse ×1
overloading ×1
sonarqube ×1