本次只讲三个东西,Lamda表达式、函数引用、函数式接口。
一、Lamda表达式
//@FunctionalInterface注解可添加默认实现的方法但是必须有且仅有一个未实现的方法
@FunctionalInterface
public interface Fly {
public void fly();
default void smile(){
System.out.println("卧槽!我居然还会笑!");
}
static void talk(){
System.out.println("天呐,我居然还会说话");
}
}
public class TestMain {
public static void main(String[] args) {
/**
* java8以前的写法
*/
Fly fly=new Fly() {
@Override
public void fly() {
System.out.println("我不知道是个啥东西,但是我会飞");
}
};
/**
* java8以后()里边写参数,这里的fly方法不需要参数
*/
Fly fly1=()->System.out.println("这是个啥玩意儿,也可以飞");
fly.fly();
fly1.fly();
fly1.smile();
/**
* lamda表达式
* 1.单行
* (param)->statement
* 2.多行
* (param)->{statement}
*/
}
}
public class TestMain02 {
@FunctionalInterface
interface Message{
void caculate(int a,int b);
}
public static void main(String[] args) {
Message message=(int a,int b) -> System.out.println(a + b);
Message message2=(a,b) -> {
int c=a + b;
System.out.println(c);
};
//上边两句是等效的,编译器会自动识别变量类型,所以这就要求@FunctionalInterface的接口
//必须只有一个未实现接口
message.caculate(1,2);
message2.caculate(2,3);
}
}
也就是说以前需要用匿名实现类来做的事情,现在只需要用Lamda表达式就可以完成,(param)->函数体,充当实现类实现的函数
二、函数引用
/**
* @Description:
* @Author: yinjunjie
* @CreateDate: 2018/5/13 16:35
* @Version: 1.0
*/
class Book{
private String name;
private int price;
public Book(String name, int price) {
this.name = name;
this.price = price;
}
public Book() {
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public static void pee(){
System.out.println("I can pee...");
}
public String hotGirls(){
return "书中自有颜如玉";
}
}
@FunctionalInterface
interface BookRef<T extends Book>{
T refBook(String name,int price);
}
@FunctionalInterface
interface BookRef2<T extends Book>{
void peeRef();
}
@FunctionalInterface
interface BookRef3{
String hotGirlsRef();
}
public class TestFuncRefer {
public static void main(String[] args) {
BookRef<Book> bookRef=Book::new;
//构造方法引用 类名::new
System.out.println(bookRef.refBook("Spring实战",100));
//静态方法引用 类名::静态方法名
BookRef2 bookRef2=Book::pee;
bookRef2.peeRef();
//普通方法引用 实例化对象名::普通方法名
BookRef3 bookRef3=new Book()::hotGirls;
System.out.println(bookRef3.hotGirlsRef());
//特定类型的任意方法引用
//Comparator接口的compare方法引用String的compareToIgnoreCase方法
Comparator<String> comparator=String::compareToIgnoreCase;
}
}
三、系统提供的函数式接口
从JDK 1.8开始为了方便用户开发专门提供了一个新的包:java.util.function,在这个包里面针对于用户有可能出现的函数式接口做了一个公共定义。
在java.util.function包之中最为核心的只有四个接口:
·功能型接口:Function;
·消费型接口:Consumer;
·供给型接口:Supplier;
·断言型接口:Predicate。
- 功能型接口 Function
@FunctionalInterface
public interface Function<T, R> {
publicR apply(T t) ;// 接收数据而后返回处理结果
}
范例:实现功能型接口的引用
·本次引用Integer类的parseInt()方法,这个方法要求接收String型数据,而后返回int型数据。
package cn.com.java;
import java.util.function.Function;
public class TestDemo {
public static void main(String[] args) {
Function<String, Integer> fun= Integer::parseInt; // parseInt()方法为static型
int num= fun.apply("100");
System.out.println(num* 2);
}
}
也就是说这种既能接收数据,又能返回结果的方法,都用Function接口定义
2、消费型接口 Consumer
@FunctionalInterface
public interface Consumer<T> {
publicvoidaccept(T t); // 只是接收数据,并没有返回值存在
}
范例:使用消费型接口,引用System.out.println()这个方法,只接收数据但是没有返回值
package cn.com.java;
import java.util.function.Consumer;
public class TestDemo {
public static void main(String[] args) {
Consumer<String> con= System.out::println;con.accept("Hello World !");
}
}
3、供给型接口 Supplier
@FunctionalInterface
public interface Supplier<T> {
publicT get();
}
本接口的方法没有参数,但是却可以返回数据。
范例:设置供给型方法引用,本次引用System.currentTimeMillis();
package cn.com.java;
import java.util.function.Supplier;
public class TestDemo {
public static void main(String[] args) {
Supplier<Long> sup= System :: currentTimeMillis;
System.out.println(sup.get());
}
}
4、·断言型接口 Predicate
@FunctionalInterface
public interfacePredicate<T> {
public boolean test(T t);
}
现在是一个判断操作,那么如果是判断操作,就使用正则验证。
范例:引用String类中的matches()方法
package cn.com.java;
import java.util.function.Predicate;
public class TestDemo {
public static void main(String[] args) {
String str= "100";// String类对象
Predicate<String> pre= str::matches;
System.out.println(pre.test("\\d+"));
}
}
以上是四个核心接口,实际上这四个接口会了,那么整个java.util.function包之中的接口就明白怎么使了。
例如,随便找一个BiFunction接口,这个接口与Function相似的,此接口定义如下:
@FunctionalInterface
public interface BiFunction<T, U, R> {
publicR apply(T t, U u);
}
虽然与Function接口不同,但是这里面可以设置两个参数。
范例:利用BiFunction接口引用一个方法
·引用方法,String类的replaceAll()方法。
package cn.com.java;
import java.util.function.BiFunction;
public class TestDemo {
public static void main(String[] args) {
String str= "hello";
BiFunction<String, String, String> bf= str::replaceAll;
System.out.println(bf.apply("l", "_"));
}
}
整个包之中的接口的功能都是类似的,实际上四个会了,所有的也就都会了。
之所以系统会提供内建的函数式接口,那么就会在大量的系统类库之中使用它。
在Collection接口里面新定义了一个forEach()方法:default void forEach(Consumer<? super T> action)
此方法是一个default方法可以直接利用接口对象调用,同时这个方法里面接收有一个消费型接口。
范例:List遍历输出
package cn.com.java;
import java.util.ArrayList;
import java.util.List;
public class TestDemo {
public static void main(String[] args) {
List<String> pro= new ArrayList<String>();
pro.add("java");
pro.add("android");
pro.add("pl/sql");
pro.add("ios");
pro.add("python");
pro.add("node.js");
// pro.forEach((s) -> System.out.println(s));// 如果只有一个参数,直接编写也可以,不用写()了
pro.forEach(s-> System.out.println(s));
}
}
在以后学习系统类的时候会大量的使用到在java.util.function包之中定义的函数式接口,所以掌握这四个接口就是掌握了整个包的使用。
网友评论