Java语言规范Java 8的第15.13节描述了这种形式的方法参考语法,用于创建构造函数引用:
ClassType :: [TypeArguments] new
Run Code Online (Sandbox Code Playgroud)
例如:
String s = "abc";
UnaryOperator<String> test0 = String::new; // String(String) constructor.
String s0 = test0.apply(s);
System.out.println("s0 = " + s0); // Prints "abc".
char[] chars = {'x','y','z'};
Function<char[], String> test1 = String::new; // String(char[]) constructor.
String s1 = test1.apply(chars);
System.out.println("s1 = " + s1); // Prints "xyz"
Run Code Online (Sandbox Code Playgroud)
一切正常,但似乎绝对任何东西(不包括原语)也可以为[TypeArguments]提供,一切仍然有效:
这是一个愚蠢的例子来证明这一点:
Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
String s2 = test2.apply("123");
System.out.println("s2 = " + s2); // Prints "123"
Run Code Online (Sandbox Code Playgroud)
提出几个问题: …
当使用Java 8流时,我经常发现我需要重构一个多语句lambda表达式.我将用一个简单的例子来说明这一点.假设我已经开始编写这段代码:
Stream.of(1, 3).map(i -> {
if (i == 1) {
return "I";
} else if (i == 3) {
return "E";
}
return "";
}).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
现在我不太喜欢map通话中的大型lambda表达式.因此,我想把它重构出来.我看到两个选项,要么我Function在我的班级中创建一个实例:
private static Function<Integer, String> mapper = i -> {
if (i == 1) {
return "I";
} else if (i == 3) {
return "E";
}
return "";
};
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
Stream.of(1, 3).map(mapper).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
或者我只是制作一个方法:
private static String map(Integer i) {
if (i == 1) {
return "I";
} else if …Run Code Online (Sandbox Code Playgroud) 我想编写一个在适当的对象上调用指定方法的方法。
需要注意的是,我希望在不更改调用方法的类(例如,实现接口)的情况下执行此操作。
我在C的函数指针中找到了想要的东西,但对于Java 7却没有找到。
这里是一些伪代码:
public class A {
... constructor ...
public String aToString(){
return "A";
}
}
public class B {
... constructor ...
public String bToString(){
return "B";
}
}
/* T::<String>mymethod stands for "Method with identifier 'mymethod'
* in Class T with return type String"
*/
public class ServiceClass {
public static void genericToString(Collection<T> c,
MethodPointer T::<String>mymethod){
for(int i=0,i<c.length,i++) {
System.out.println(c.get(i).mymethod());
}
}
public static void main(){
ArrayList<A> listA = new ArrayList<A>();
listA.add(new A());
ServiceClass.genericToStringOutput(listA, A::<String>aToString); …Run Code Online (Sandbox Code Playgroud) 我不明白为什么code1工作但code2不编译.请解释.
//Code1:
Stream<String> s = Stream.of("AA", "BB");
s.sorted(Comparator.reverseOrder())
.forEach(System.out::print);
//Code2:
Stream<String> s = Stream.of("AA", "BB");
s.sorted(Comparator::reverseOrder)
.forEach(System.out::print);
Run Code Online (Sandbox Code Playgroud)
两者之间的区别是code2使用Comparator.reverseOrder()时code1使用Comparator::reverseOrder
这是我的第一个代码:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator.reverseOrder()).forEach(System.out::print);
//...
}
}
Run Code Online (Sandbox Code Playgroud)
结果:灰熊熊
这是我的第二个代码:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator::reverseOrder()).forEach(System.out::print);
//...
}
}
Run Code Online (Sandbox Code Playgroud)
结果:编译器错误
我的问题:为什么第二个代码中存在编译器错误?我不能将方法参考用于功能接口的静态方法吗?
我知道我不能使用方法引用和函数接口的默认方法.我知道我可以在5种情况下使用类的方法引用:
类
类:: STATICMETHOD
类:: instanceMethod
例如:: instanceMethod
类::新
功能界面
非常感谢!
我尝试以与 Java 中相同的方式使用方法引用:
button.setOnClickListener(this::clickListener);
Run Code Online (Sandbox Code Playgroud)
使用科特林:
button.setOnClickListener {this::clickListener}
Run Code Online (Sandbox Code Playgroud)
但是这在 Kotlin 中不起作用,解决方案是使用 labmda 表达式实际调用函数:
button.setOnClickListener {clickListener()}
Run Code Online (Sandbox Code Playgroud)
为什么 Kotlin 在这种情况下不接受方法引用?和Java的原理不一样吗?
假设我有一个HashMap作为Map<Integer, List<Integer>> map = new HashMap<>();。
现在List<Integer> values = computeIfAbsent(key, ArrayList::new);可以正常工作,但是List<Integer> values = computeIfAbsent(key, LinkedList::new);会引发编译错误。
我可以在ArrayList和LinkedList中看到no-arg构造函数。我在这里想念的是什么,有人可以解释这种现象吗?
假设我们的方法接收输入 String并返回一些List output。此输出是一些生成器的结果,其中一些生成器取决于输入,而有些则不取决于输入-它们只是添加预定义的值。我想将这些生成器实现为一些函数接口的列表(例如,Consumer),然后将它们组合到一个Consumer中,然后将其应用于输入String。
因此,我将能够轻松,独立地更换小型发电机。但是问题在于,并非我的所有生成器都需要输入 String作为参数,而我只是出于一个原因就将这个参数传递给了它-能够将此类使用者与其他使用者组合在一起。
public class ConsumersTest {
private static <T, U> BiConsumer<T, U> combine(List<BiConsumer<T, U>> consumers) {
return consumers.stream().reduce((arg1, arg2) -> {}, BiConsumer::andThen);
}
List<String> generate(String input) {
ArrayList<String> output = new ArrayList<>();
combine(getGenerators()).accept(input, output);
return output;
}
private List<BiConsumer<String, List<String>>> getGenerators() {
return Arrays.asList(
this::addFirstDependent,
this::addSecondIndependent
);
}
private void addFirstDependent(String input, List<String> output) {
if (input.contains("some string")) {
output.add("First-Dependent");
}
}
private void addSecondIndependent(String input, List<String> output) {
output.add("Predefined Output");
}}
Run Code Online (Sandbox Code Playgroud)
是否可以将不同的消费者合并到一个保护伞下并在一个地方应用?还是这是一个坏主意,而不是正确的方法?
试图理解方法引用,但我很难理解。坚持比较器示例。
为了让我的大脑更轻松,我一直从基础开始(匿名类实现 >> laba 表达式 >> 方法引用)它是方法引用和比较器示例,我无法让它工作。
我想排序的 POJO(从一些互联网示例中提取 - mkyong)
public class Fruit{
private int quantity;
private String name;
....
}
Run Code Online (Sandbox Code Playgroud)
创建要使用的测试数据:
Fruit[] fruits = new Fruit[3];
Fruit pineapple = new Fruit("pineapple",10);
Fruit orange= new Fruit("orange",4);
Fruit kiwi= new Fruit("kiwi",15);
fruits[0] = pineapple;
fruits[1] = orange;
fruits[2] = kiwi;
Run Code Online (Sandbox Code Playgroud)
匿名排序类实现:
Comparator<Fruit> anonymousSortByname = new Comparator<Fruit>(){
public int compare(Fruit f1,Fruit f2){
return f1.getName().compareTo(f2.getName());
}
};
Run Code Online (Sandbox Code Playgroud)
排序 :
Arrays.sort(fruits,anonymousSortByname);
Run Code Online (Sandbox Code Playgroud)
既然这可行,我已经明白匿名类可以转换为 lambda 表达式(前提是它们是功能接口等......)
Lambda 实现:
Comparator<Fruit> lambdaSortByname =
(Fruit f1,Fruit f2) -> …Run Code Online (Sandbox Code Playgroud) 我了解,如果所引用的方法与功能接口具有相同数量的args并返回相同的类型,则可以使用方法引用来实现功能接口,但是为什么在某些情况下,所引用的方法与功能接口具有不同数量的args但仍然兼容吗?
我有一个简单的BiConsumer,我尝试使用方法引用来实现它。我知道只要args的数量匹配,我也可以使用lambda表达式。我将显示代码以清楚地说明它。
我有一个BiConsumer<ArrayList<String>, ? super String>我要实现的。
Lambda表达式的实现方式是:
BiConsumer<ArrayList<String>, ? super String> b = (firstArg,secondArg) -> firstArg.add(secondArg); 由于它们都带有2个输入参数,因此没有问题。
但是为什么BiConsumer<ArrayList<String>, ? super String> a = ArrayList::add;也兼容?addArrayList上的方法仅需要1个输入args,而功能接口则需要2个。
任何答案将不胜感激。谢谢!
method-reference ×10
java ×8
java-8 ×6
lambda ×4
android ×1
java-7 ×1
java-stream ×1
kotlin ×1