JDK8 新特性分析及实践(一)---接口新特性&lambda表达式

JDK8 新特性分析及实践(一)---接口新特性&lambda表达式_第1张图片



文章目录

    • 一、JDK8 简介
      • 1.1 概述
      • 1.2 新特性介绍
    • 二、JDK8 接口新特性
      • 2.1 概述
      • 2.2 应用场景
      • 2.3 快速入门分析
        • 2.3.1 default方法设计及实现
        • 2.3.2 接口中的static方法设计及实现
        • 2.3.3 函数式接口设计及实现
        • 2.3.4 应用案例增强分析及实现
    • 三、Lambda 表达式应用
      • 3.1 概述
      • 3.2 应用场景
      • 3.3 快速入门分析
      • 3.4 应用案例增强分析及实现?
        • 3.4.1 简化线程对象创建
        • 3.4.2 简化排序操作的实现



一、JDK8 简介

1.1 概述

Java 8由Oracle从2014年3月18日发布,此版本是自Java 5(发布于2004年)之后的一个重量级版本,也是java发展史上的一个里程碑式的版本。这个版本在JVM、编译器、库、Java语法特性等方面都做了很大改进,同时在语言的表达力、简洁性等个方面也有了很大的提高。目前几乎所有的JAVA框架也都已升级到支持JDK8,打开框架源码想了解其设计,假如不理解JDK8的这些特性看起来就会非常吃力。所以我们设计了这个专题,我们将在这个专题中讲解JDK8中的部分关键特性,并用实际案例讲解这些特性应用,希望同学们在JDK8技术的应用上有一个很好的提高。

1.2 新特性介绍

Java 8这个版本提供了很多实用的新特性,针对接口推出了接口默认方法,接口静态方法以及函数式接口,同时为了简化代码编写,推出了lambda表达式,为了增强对数据的操作,还定义了Stream操作等。这个版本目前是市场上一个应用最广泛,也是最重要的一个版本。

二、JDK8 接口新特性

2.1 概述

JDK8中对接口规范进行了新的定义,允许在接口中定义默认方法(使用default关键字修饰),静态方法,同时还推出了函数式接口(使用@FunctionInterface注解描述)设计。

2.2 应用场景

基于JDK8中接口新规范的定义,不仅可以扩展接口新功能(新的标准),还能保持接口向前兼容的特性。例如Java API中的集合操作规范。

2.3 快速入门分析

2.3.1 default方法设计及实现

JDK8中为了对接口业务进行扩展,但又不影响实现类,提供了默认方法。此类型的方法使用default关键字修饰,可以有方法体的实现。例如:

interface IA{
     
        default void doMethod01() {
     
                System.out.println("doMethod01");
        }
        default void doMethod02() {
     
                System.out.println("doMethod02");
        }
}

接口默认方法提高了编程的灵活度,一个类在实现接口时,接口中假如有默认方法,默认方法可以有选择性的对其进行重写,但不是必须要重写,例如:

class ClassA implements IA{
     }

接口默认方法,解决了java8和以前接口版本特性的兼容性问题,对于我们以后的程序开发,可以在接口子类中直接使用接口默认方法,而并不再需要在各个子类中都去实现这些方法了。
案例展示(一):

package com.cy.java8.interf;
/**
 * 抽象方法添加的时候,子类不重写的话会出错
 * 默认方法的好处:扩展方法的时候,不会出现其他的错误,向前考虑
 * @author lixin
 */
//接口
interface IA {
     
	//默认方法
	default void doMethod01() {
     
		System.out.println("doMethod01()...");
	}
	default void doMethod02() {
     
		System.out.println("doMethod02()...");
	}
	void doMethod03();//抽象方法
}

class ClassA implements IA{
     
	//默认方法的重写
	@Override
	public void doMethod01() {
     
		// TODO Auto-generated method stub
		IA.super.doMethod01();//需要注意的地方
		System.out.println("ClassA.doMethod01()...");
	}
	//普通方法的重写
	@Override
	public void doMethod03() {
     
		System.out.println("doMethod03()...");
	}
}

public class TestInterfaceDefaultMethod01 {
     
	public static void main(String[] args) {
     
		IA a1 = new ClassA();
		a1.doMethod01();
		a1.doMethod03();
	}
}

案例展示(二):

package com.cy.java8.interf;

interface IC {
     
	//抽象方法
	default void doMethod01() {
     };
	default void doMethod02() {
     };
}

@Deprecated //提示过时的类
class AbstractICAdapter implements IC {
     //钩子方法,早期的写法
	@Override
	public void doMethod01() {
     
	}
	@Override
	public void doMethod02() {
     	
	}
}
//class ClassC implements IC{}
class ClassC extends AbstractICAdapter{
     
	@Override
	public void doMethod01() {
     
//		super.doMethod01();
		System.out.println("doMethod01()...");
	}
}

public class TestInterfaceDefaultMethod02 {
     
	public static void main(String[] args) {
     
		IC c1 = new ClassC();
		c1.doMethod01();
	}
}

2.3.2 接口中的static方法设计及实现

Java8中的接口规范,不仅允许定义多个默认方法,也允许在接口中定义多个静态方法,这些静态方法类似于 class 中的静态方法,可以通过接口名进行直接调用。

interface IB{
     
        static void doMethod() {
     
                System.out.println("doMethod()");
        }
}

接口中静态方法并不能在实现类中被覆写,实现类中可以声明相同的方法,但这两个方法之间除了名字相同,并没有 override 关系。

案例展示:

package com.cy.java8.interf;

//接口里面的静态方法
interface IStatic{
     
	public static void doPrint(){
     
		System.out.println("IStatic.doPrint()");
	}
}

class ClassStatic implements IStatic{
     
	public static void doPrint(){
     
		System.out.println("ClassStatic.doPrint()");
	}
} 


public class TestInterfaceStaticMethod01 {
     
	public static void main(String[] args) {
     
		IStatic s1 = new ClassStatic();
//		s1.doPrint();
		IStatic.doPrint();//IStatic.doPrint()
		
		ClassStatic s2 = new ClassStatic();
		s2.doPrint();//ClassStatic.doPrint()
		
		ClassStatic.doPrint();//正确的调用方式
		
	}
}

2.3.3 函数式接口设计及实现

Java8引入了一个是函数式接口(Functional Interfaces),此接口使用 @FunctionalInterface修饰,并且此接口内部只能包含一个抽象方法。

@FunctionalInterface
public interface Comparator<T> {
     
	int compare(T o1, T o2);  // public abstract
}

说明:函数式接口推出的目的主要是为了配合后续Lambda表达式的应用。

案例展示:

package com.cy.java8.interf;
/**
 * @FunctionalInterface 描述的接口为函数式接口,此接口内部只允许有一个抽象方法
 * @author lixin
 *
 */
@FunctionalInterface
interface Fun{
     
	void doMethod01();
	//函数式接口中只允许有一个方法是抽象的
//	void doMethod02();
	default void doMethod02() {
     }
} 

public class TestFunctionInterface01 {
     
	public static void main(String[] args) {
     
		new Fun() {
     
			
			@Override
			public void doMethod01() {
     
				// TODO Auto-generated method stub
				System.out.println("doMethod01()");
			}
		}.doMethod01();
	}
}

2.3.4 应用案例增强分析及实现

在JDK中的java.util.function包中定义了大量函数式接口。常用的有如下几个:

(1)消费型接口(特点:方法有入参,没有返回值)

@FunctionalInterface
public interface Consumer<T> {
     
	void accept(T t);
    ...
}

(2)函数式接口(特点:方法有入参,有返回值)

@FunctionalInterface
public interface Function<T, R> {
     
	R apply(T t);
    ...
}

(3)判定式接口(特点:方法有入参,返回值为boolean)

@FunctionalInterface
public interface Predicate<T> {
     
	boolean test(T t);
	...
}

(4)供给式接口(特点:方法没有入参,但有返回值)

@FunctionalInterface
public interface Supplier<T> {
     
	T get();
	...
}

说明:这些接口可以配合Lambda使用以减少我们自己接口的定义。

案例展示:

package com.cy.java8.interf;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class TestFunctionInterface02 {
     
	public static void main(String[] args) {
     
		//1.消费型接口
		Consumer<String> consumer = new Consumer<String>() {
     
			@Override
			public void accept(String t) {
     
				// TODO Auto-generated method stub
				System.out.println(t);
			}
		};
		consumer.accept("hello world");
		
		//2.函数式接口
		Function<String, Integer> function = new Function<String, Integer>() {
     
			@Override
			public Integer apply(String t) {
     
				// TODO Auto-generated method stub
				return Integer.parseInt(t);
			}
		};
		Integer result = function.apply("100");
		System.out.println(result);
		
		//3.判定型接口
		Predicate<String> predicate = new Predicate<String>() {
     
			List<String> list = Arrays.asList("A","B","C");
			@Override
			public boolean test(String t) {
     
				// TODO Auto-generated method stub
				return list.contains(t);
			}
		};
		System.out.println(predicate.test("A"));
		
		//4.供给型接口
		Supplier<Object> supplier = new Supplier<Object>() {
     
			@Override
			public Object get() {
     
				// TODO Auto-generated method stub
				return new Object();
			}
		};
		System.out.println(supplier.get());
		//...
	}
}

三、Lambda 表达式应用

3.1 概述

Java中的Lambda表达式是JDK8中的一种新特性,它允许我们将一段代码(这段代码可以理解为一个接口的实现)当成参数传递给某个方法,然后进行业务处理,这种方式更像是一种函数式编程风格,可以让代码结构更简洁,开发效率更高。

3.2 应用场景

Java中的Lambda为JAVA编程注入了函数式编程思想,在迭代操作,映射操作,聚合操作等很多方面的实现上做出了很大努力。并从语法角度简化了程序员对特定代码的编写,通过底层的类型推断,方法引用等特性让代码表现的更加优雅。现在已成为我们编程过程中常用的一种编程方式。

3.3 快速入门分析

最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块组成,例如:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

在上面这个代码中的参数e的类型是由编译器推理得出的,你也可以显式指定该参数的类型,例如:

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );

案例展示:

package com.cy.java8.lambda;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;

public class TestLambda01 {
     
	public static void main(String[] args) {
     
		
		List<String> list = Arrays.asList("A","B","C");
		for (String s : list) {
     
			System.out.println(s);
		}
		
		System.out.println("=========");
		list.forEach(new Consumer<String>() {
     //匿名内部类
			@Override
			public void accept(String t) {
     
				// TODO Auto-generated method stub
				System.out.println(t);
			}
		});
		System.out.println("====lambda表达式写法===");
		list.forEach((s)->System.out.println(s));
	}
}

如果Lambda表达式需要更复杂的语句块,则可以使用花括号将该语句块括起来,类似于Java中的函数体,例如:

Arrays.asList( "a", "b", "d" ).forEach( e -> {
     
	System.out.print( e );
	System.out.println( );
} );

lambda 表达式可以让代码编写更加简洁。我们先来思考下普通的函数或方法具备的几个元素:

  • 访问修饰符
  • 返回值类型
  • 方法名
  • 参数列表
  • 代码块

在lambda 表达式应用过程中,你应该也注意到了,一般只有两个元素:

(parameter list) -> body

其中“->”将参数列表与函数主体分离,旨在对给定参数进行处理。函数的主体可能是一条或多条语句。例如其常见结构如下:

() -> statement
arg -> statement
(arg1, arg2, ...) -> {
       body-block }
(Type1 arg1, Type2 arg2, ...) -> {
      method-body-block;return value; }

Lambda表达式有返回值,返回值的类型也由编译器推理得出。如果Lambda表达式中的语句块只有一行,则可以不用使用return语句,下列两个代码片段效果相同:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
     
	int result = e1.compareTo( e2 );
	return result;
} );

案例展示:

package com.cy.java8.lambda;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class TestLambda02 {
     

	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		List<String> list = Arrays.asList("C","B","A");
		
		//匿名内部类
		list.sort(new Comparator<String>() {
     
			@Override
			public int compare(String o1, String o2) {
     
				// TODO Auto-generated method stub
				return o1.compareTo(o2);
			}
		});
		System.out.println(list);
		
		System.out.println("====lambda表达式====");
		list.sort((o1,o2) -> o1.compareTo(o2));
		System.out.println(list);	

	}
}

3.4 应用案例增强分析及实现?

结合对象lambda表达式基本语法的认识,分析如下案例:

3.4.1 简化线程对象创建

构建一个线程对象,执行Runnable类型的任务,传统方式的实现,其关键代码如下:

new Thread(new Runnable() {
     
	@Override
	public void run() {
     
		System.out.println("hello");
	}
}).start();

基于JDK8中的Lambda表达式实现方式,对传统方式线程对象的创建进行简化,其关键代码如下:

new Thread(()->{
     
	System.out.println("hello");
}).start();

案例展示:

package com.cy.java8.lambda;

public class TestLambda03 {
     

	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		new Thread(new Runnable() {
     
			@Override
			public void run() {
     
				// TODO Auto-generated method stub
				System.out.println("Execute task");
			}
		}).start();
		
		//=====lambda=====
		new Thread(()->System.out.println("execute task")).start();
	}

}

3.4.2 简化排序操作的实现

定义一字符串数组,然后对字符串数组中的内容,按字符串元素的长度对其进行排序。代码如下:

String[] strArray= {
     "abcd","ab","abc"};                

在JDK8之前传统的实现方案,基于Arrays类对数组中的元素进行排序操作,关键代码实现如下:

Arrays.sort(strArray,new Comparator<String>() {
     
	@Override
	public int compare(String o1, String o2) {
     
		return o1.length()-o2.length();
	}
});

基于JDK8中的Lambda表达式,对排序如上排序方案的代码实现过程进行简化,关键代码如下:

Arrays.sort(strArray, (s1, s2) -> s1.length() - s2.length());

案例展示:

package com.cy.java8.lambda;

import java.util.Arrays;
import java.util.Comparator;

public class TestLambda04 {
     

	public static void main(String[] args) {
     
		
		String[] strArray = {
     "b","DFEL","bcd"};
		Arrays.sort(strArray,new Comparator<String>() {
     
			@Override
			public int compare(String o1, String o2) {
     
				return o1.length()-o2.length();
			}
		});
		
		System.out.println("======Lambda表达式======");
		Arrays.sort(strArray,(String o1,String o2)->{
     
			return o1.length()-o2.length();
		});
		
		Arrays.sort(strArray,(o1,o2)->o1.length()-o2.length());
	}
}

下篇预告:

  • 方法
  • Stream式操作应用
  • 日期对象的应用

你可能感兴趣的:(Java核心,java)