这个标题有点意思
Java8的明显特点是通过默认接口定义、Lambda表达式、方法引用、函数式接口带来了函数式编程,这些功能的出现也改变了java多年来的一些习惯
接口定义增强:
这是一个极其毁三观的方式
java的接口一直是由全局常量和抽象方法组成,但是在Java8出现后,这一个形势就因此改变了…
场景:存在一个接口,而同时有2k个类实现了该接口,突然有一天需求更改,需在接口里添加一个方法,而所有实现该接口的子类该方法的实现是一样的,按照之前的方式,需在每一个子类复写该方法,so….你需要复制粘贴2k次
为了解决这个问题,default就诞生了
default示例
interface Formula { double calculate(int a); default double sqrt(int a) { return Math.sqrt(a); } //static方式 static void get(){ system.out.println("..."); } } Formula formula = new Formula() { @Override public double calculate(int a) { return sqrt(a * 100); } }; formula.calculate(100); // 100.0formula.sqrt(16); // 4.0//static方式Formula.get();
除了用default定义方法,一旦使用了static定义方法意味着这个方法只可以直接由类名称调用。
另外还有一个重要概念:内部类访问方法参数的时候可以不加上final关键字
Lambda表达式
lambda属于函数式编程的概念
传统的匿名内部类,Android中添加监听器的典型例子
Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "Button Clicked", Toast.LENGTH_SHORT).show(); } });
这段代码好繁琐
这个代码认真一看,其实主要运用到的代码仅仅只有Toast使用的这一句,但由于java的面向对象语法,不得不嵌套更多内容
做法太过严谨,于是java8引入了函数式编程简化语法
怎么简化呢?
Lambda范例:
Button button = (Button) findViewById(R.id.button); button.setOnClickListener(v->Toast.makeText(MainActivity.this, "Button Clicked", Toast.LENGTH_SHORT).show());
长度减了一大半,使用了Lambda表达式大大简化了语法
道理我都懂,怎么使用?
Lambda语法三种形式
(参数)->单行语句; () -> System.out.println(“hello”)
(参数)->{单行语句}; (String s) -> { System.out.println(s); }
(参数)->表达式 (int x, int y) -> x + y
范例:
public void runnableTest() { // 一个匿名的 Runnable Runnable r1 = new Runnable() { @Override public void run() { System.out.println("Hello world one!"); } }; // Lambda Runnable Runnable r2 = () -> System.out.println("Hello world two!"); // 执行两个 run 函数 r1.run(); r2.run(); }
让我再举一个简化变得更短的例子
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia"); Collections.sort(names, (String a, String b) -> b.compareTo(a));//让他再变得更短些 Collections.sort(names, (a, b) -> b.compareTo(a));
嘿嘿,看明白了吗
当只有一个表达式时,那么会直接进行返回操作
方法引用
以前更多的是在对象上使用引用,而java8多出的是方法引用
这是什么鬼?
待会再跟你解释.
方法引用需要使用 :: 关键字,这是java8才有的东东
接下来,让我们说说四种形式方法引用:
引用静态方法:类名称 :: static 方法名称;
引用某个对象的方法:实例化对象 :: 普通方法;
引用特定类型的方法:特定类 :: 普通方法
引用构造方法:类名称 :: new
例子:引用静态方法:
在String类里面有一个valueOf()方法:public static String valueOf(int x);
interface Inter<P,R>{ public R zhuanhuan(P p); } public class Test{ public static void main(String args[]){ Inter<Integer,String> msg = String::valueOf; String str = msg.zhuanhuan(3000); System.out.println(str); // 3000 //原始方法 Inter<Integer, String> msg = new Inter<Integer, String>() { public String zhuanhuan(Integer p) { return String.valueOf(p); } }; //lambda Inter<Integer, String> msg =(p)->String.valueOf(p); } }
通过
Inter<Integer,String> msg = String::valueOf;
让Inter的R方法拥有了valueOf的功能
卧槽,这….不就是传说中的直接复制敌人绝招嘛,
将String.valueOf()方法变为了Inter接口里的R()方法,
再来另外三个例子看看?
例子:引用普通方法:
@FunctionalInterface //此为函数式接口,只能定义一个方法interface Inter<P,R>{ public R upper(); //public void print();}public class Test{ public static void main(String args[]){ //要在实例化对象下使用 //hello是String的实例化对象 Inter<Integer,String> msg = "hello"::toUpperCase; String str = msg.Upper(); System.out.println(str); // HELLO } }
此时我们应该有了疑问:
通过两个代码演示,如果要实现函数引用,接口里必须只存在一个方法。如果再来一个方法,方法不是无法引用了吗?如划线语句
//public void print();
所以为了保证被引用接口里面只有一个代码,需加上注解@FunctionalInterface 此为函数式接口
之前引用的方式中,都是静态方法,
接下来我们试试引用普通方法需实例化
例子:引用特定类方法 ,比较方法public int compareTo(String anotherString);
interface Inter<P>{ public int compare(P p1,P p2); }public class Test{ public static void main(String args[]){ Inter<String> msg = String::compareTo; System.out.println(msg.compare("A","B")); // -1 } }
与之前相比,方法引用前不再需要定义对象,而是可以理解为将对象定义在了参数上
例子:引用构造方法
又一个毁三观的功能
interface Inter<C>{ public C create(String t,double p); }class Book { private String title; private double price; public Book(String title,double price){ this.title = title; this.price = price; } public String toString(){ return "book name:"+this.title+",book price:"+this.price; } }public class Test{ public static void main(String args[]){ Inter<Book> msg = Book::new; Book book = msg.create("java",20); System.out.println(book);//book name:java,book price:20 } }
那为啥java8不定义这些接口直接给我们使用呢?
当然有啦
函数式接口
jdk8提供了一个函数式接口包java.util.function,里面有众多的函数式接口,而其中最基础最常操作的有以下四个核心接口:
功能型接口:
public interface Function<T,R>{public R apply(T t);}
接收一个参数 返回一个结果
例如String.valueOf()
消费型接口:
public interface Consumer<T>{public void accept(T t);}
接收参数 不返回结果
例如System.out.println
供给型接口:
public interface Supplier<T>{public void get(T t);}
不接收参数 返回结果
例如String的toUpperCase()
断言型接口:
public interface Predicate<T>{public boolean test(T t);}
判断操作使用
例如String的equalsIgnoreCase()
说这些,来个例子?
public class Test{ public static void main(String args[]){ //功能型接口 Function<String,Boolean> fun = "hello"::startsWith; System.out.println(fun.apply("he")); //true //消费型接口 Consumer<String> cons = System.out::println; cons.accept("hello"); //hello //供给型接口 Supplier<Stirng> sup = "hello"::toUpperCase; System.out.println(sup.get()); //HELLO //断言型接口 Predicate<String> pre ="hello"::equalsIgnoreCase; System.out.println(pre.test("Hello")); //true } }
这几个接口包含的各种引用,也是函数式接口的代表,那么存在其他的众多接口中,都是这四个接口的扩展提升
So,这些就是Java8带来的新特性啦
多多实践有利掌握