functional interface and method reference
Published:
Java basics – functional interface and method reference
Functional interface and method reference
Functional interface
Concept
An interface with only one abstract method is called a functional interface
Format
Modifier interface interface name {
public abstract return value type method name (optional parameter information);
//Other non-abstract method content
}
Among them, public abstract
can be omitted
@FunctionalInterface annotation
Can detect whether the interface is a functional interface
@FunctionalInterface
Modifier interface interface name {
public abstract return value type method name (optional parameter information);
//Other non-abstract method content
}
Use
Generally used as a method parameter or return value type
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
//transfer
show(new MyFunctionalInterfaceImpl());
show(new MyFunctionalInterface(){
@Override
public void method(){
//...
}
});
show(()->{
//...
});
Functional Programming
Use Lambda as parameter and return value
Use functional interfaces as method parameters
public static void startThread(Runnable run){ new Thread(run).start(); } public static void main(String[] args){ startThread(()->{ //... }); }
Use a functional interface as the return value of a method
public static Comparator<String> getComparator(){ return (o1,o2)->o1.length()-o2.length(); }
Commonly used functional interface
Many functional interfaces are provided in the java.util.function package
Supplier interface
The java.util.function.Supplier<T>
interface only contains a parameterless method T get()
, which returns generic type data (production interface)
public static String getString(Supplier<String> sup){
return sup.get();
}
public static void main(String[] args){
String str=getString(()->"abc");
}
Consumer interface
The abstract method of java.util.function.Consumer<T>
interface void accept(T t)
(consumer interface)
public static void setString(String name, Consumer<String> con){
con.accept(name);
}
public static void main(String[] args){
setString("abc",(name)->System.out.println(name));
}
Default method: andThen
default Consumer<T> andThen(Consumer<? super T> after)
, combine two operations
public static void setString(String name, Consumer<String> con1, Consumer<String> con2){
con1.andThen(con2).accept(name);
}
Predicate interface
java.util.function.Predicate<T>
is used to judge data of a certain data type and get a boolean value
Abstract method: test
boolean test(T t)
public static boolean check(String s, Predicate<String> pre){ return pre.test(s); } public static void main(String[] args){ String s="aaa"; boolean b=check(s,(s)->s.length()>5); }
Default method: and, or, negate
default Predicate<T> and(Predicate<? super T> other)
public static boolean check(String s, Predicate<String> pre1, Predicate<String> pre2){ return pre1.and(pre2).test(s); } public static void main(String[] args){ String s="aaa"; boolean b=check(s,(s)->s.length()>5,(s)->s.contains("a")); }
default Predicate<T> or(Predicate<? super T> other)
public static boolean check(String s, Predicate<String> pre1, Predicate<String> pre2){ return pre1.or(pre2).test(s); } public static void main(String[] args){ String s="aaa"; boolean b=check(s,(s)->s.length()>5,(s)->s.contains("a")); }
default Predicate<T> negate()
public static boolean check(String s, Predicate<String> pre){ return pre.negate().test(s); } public static void main(String[] args){ String s="aaa"; boolean b=check(s,(s)->s.length()>5); }
Function interface
java.util.function.Function<T,R>
is the conversion type interface
Abstract method: apply
R apply(T t)
public static void change(String s, Function<String,Integer> fun){ System.out.println(fun.apply(s)); } public static void main(String[] args){ String s="1234"; change(s,(s)->Integer.parseInt(s)); }
Default method: andThen
For combined operations
public static void change(String s, Function<String,Integer> fun1, Function<Integer,String> fun2){ System.out.println(fun1.andThen(fun2).apply(s)); } public static void main(String[] args){ String s="1234"; change(s,(s)->Integer.parseInt(s),(s)->s+"!"); }
Stream
Stream appeared after JDK1.8+, focusing on what to do instead of how to do it
list<String> list=new ArrayList();
list.add("abc");
list.add("aaaa");
list.add("bbbb");
list.add("aer");
list.stream().filter(name->name.startsWith("a")).filter(name->name.length()==3).foreach(name->System.out.println(name)) ;
Flow Thinking
Stream is a message queue from a data source
- Elements are objects of a specific type, forming a queue (no elements are stored)
- Data source: the source of the stream, which can be an array, a collection, etc.
- Features:
- Pipelining: Intermediate operations will return the stream object itself, and multiple operations can be chained into a pipeline
- Internal iteration: You can directly call the traversal method
Steps for usage:
- Get a data source
- Data Conversion
- Perform operations and get results
Note:
Stream is a pipeline stream, which can only be used once, and no other methods can be called after use
Get the stream
The java.util.stream.Stream
Ways to get the stream:
- All Collections can use the
stream
default method to get the streamdefault Stream<E> stream()
- The static method
of
of the Stream interface can get the stream corresponding to the arraystatic <T> Stream<T> of(T... values)
Common methods
- Delay method: the return type is still a method of the Stream interface’s own type
- final method: a method whose return type is not the type of the Stream interface itself
One by one: foeEach
void forEach(Consumer<? super T> action)
This method is a final method
Filter: filter
Stream<T> filter(Predicate<? super T> predicate)
This method is a delayed method
Mapping: map
<R> Stream<R> map(Function<? super T,? Extends R> mapper)
This method is a delayed method
Statistics:count
long count()
This method is a final method
Take the first few: limit
Stream<T> limit(long maxSize)
This method is a delayed method
Skip the first few: skip
Stream<T> long(long n)
This method is a delayed method
Combination: concat
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
Note: this is a static method
Usage example:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); stream.filter(i->i>=2&&i<=4).map(i->i+"!").forEach(i-> System.out.println(i)); Stream<String> stream1 = Stream.of("abc", "aaa", "def", "ddd", "abc", "aaa", "def", "ddd"); long count = stream1.limit(5).count(); System.out.println(count); Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6, 7); stream2.skip(3).forEach(i-> System.out.println(i)); Stream<Integer> stream3 = Stream.of(1, 2, 3); Stream<Integer> stream4 = Stream.of(4, 5, 6); Stream.concat(stream3,stream4).forEach(i-> System.out.println(i));
Method reference
Redundant Lambda Expression
@FunctionalInterface public interface Printable{ publc void print(String s); } public class Main{ public static void printString(Printable p){ p.print("Hello World"); } public static void main(String[] args){ printString(s->System.out.println(s)); printString(System.out::println); } }
Format
The double colon
::
is a reference operator, and the expression in which it is used is a method reference.If the function scheme to be expressed by Lambda already exists in the implementation of a method, you can use method reference instead of Lambda expression
Note: The parameters passed in Lambda must be the type that the method in the method reference can receive, otherwise an exception will be thrown
Referencing member methods by object name
Prerequisite: The object already exists, and the member method already exists
class MethodObject{ public void printUppercaseString(String s){ System.out.println(s.toUpperCase()); } } @FunctionalInterface interface Printable{ public void print(String s); } public class Main { public static void printString(Printable p){ p.print("Hello World"); } public static void main(String []args) { MethodObject obj=new MethodObject(); printString(obj::printUppercaseString); } }
Referencing static methods by class name
Prerequisite: the class exists, the static method exists
class MethodObject{ public static void printLowercaseString(String s){ System.out.println(s.toLowerCase()); } } @FunctionalInterface interface Printable{ public void print(String s); } public class Main { public static void printString(Printable p){ p.print("Hello World"); } public static void main(String []args) { printString(MethodObject::printLowercaseString); } }
Use super to reference parent class member methods
Prerequisite: The parent class exists and the member method exists
class MethodObject{ public void printnum(String s) { int num=Integer.parseInt(s); System.out.println(num-1); } } class MethodObjectSon extends MethodObject{ @Override public void printnum(String s) { int num=Integer.parseInt(s); System.out.println(num+1); } public void method(Printable p){ p.print("123"); } public void show(){ method(super::printnum); } } @FunctionalInterface interface Printable{ public void print(String s); } public class Main { public static void main(String []args) { new MethodObjectSon().show(); } }
Refer to this class member method through this
Prerequisite: this class exists, member methods exist
class MethodObject{ public void printUpper(String s) { System.out.println(s.toUpperCase()); } public void method(Printable p){ p.print("abc"); } public void show(){ method(this::printUpper); } } @FunctionalInterface interface Printable{ public void print(String s); } public class Main { public static void main(String []args) { new MethodObject().show(); } }
Class constructor reference
Reference class construction method
class MethodObject{ public MethodObject(String s){ System.out.println("MethodObject constructor! "+s); } public MethodObject(){} public void method(Printable p){ p.print("abc"); } public void show(){ method(MethodObject::new); } } @FunctionalInterface interface Printable{ public void print(String s); } public class Main { public static void main(String []args) { new MethodObject().show(); } }
Array constructor reference
@FunctionalInterface interface ArrayBuilder{ int[] buildArray(int length); } public class Main { public static int[] initArray(int length, ArrayBuilder builder){ return builder.buildArray(length); } public static void main(String []args) { int[] array=initArray(10,int[]::new); System.out.println(array.length); } }