Java8新特性小结-接口与Lambda表达式

Java8的新特性相对于前版本(Java7)来说,主要体现在两个方面:

1.   接口定义与使用

2.   Lambda表达式对匿名内部类的简化使用。

Java8新特性的具体表现如下:

1.在接口中的体现

(1)在接口中可以定义实体方法,但除原先的抽象方法外只能定义两种方法:

A.公共的静态方法

如:

package com.jasberyon.java8.interfacer;

public interface InterfaceA {

	public static void sayHi(){
		System.out.println("InterfaceA---sayHi");
	}
}

需要注意的是:

a.由于静态方法是属于类(文件)的,所以调用时需要使用对应的接口(静态方法所在类)名去调用。所以在Java8中调用接口中静态方法时,只能通过接口名去调用,使用实现类是无法调用的。

B.使用default关键字声明的普通方法

如:

<span style="font-size:12px;">package com.jasberyon.java8.interfacer;

public interface InterfaceA {

	public default void sayHi2(){
		System.out.println("InterfaceA---sayHi2");
	}
}
</span>

需要注意的是:

b.default关键字只能在接口中使用。那么当在接口的具体实现类中重写该default关键之标识的方法时就需要去掉default关键字。如:

package com.jasberyon.java8.interfacer;

public class InterfaceImpl implements InterfaceA {

	public static void main(String[] args){
		InterfaceA.sayHi();
		InterfaceImpl.sayHi();
	}

	public static void sayHi(){
		System.out.println("InterfaceImpl---sayHi");
	}

	public void sayHi2(){
		System.out.println("InterfaceB---sayHi2");
	}
}

在上面的代码情况(重写接口中的default关键字标识的方法)下当多态调用时,同样会走现实类(子类)的方法,如果没有重写,则走接口中的default方法。

例如:

package com.jasberyon.java8.interfacer;

public class InterfaceImpl implements InterfaceA {

	public static void main(String[] args){
		InterfaceA.sayHi();
		InterfaceImpl.sayHi();
		InterfaceA ia = new InterfaceImpl();
		ia.sayHi2();
	}

	public static void sayHi(){
		System.out.println("InterfaceImpl---sayHi");
	}

	public void sayHi2(){
		System.out.println("InterfaceB---sayHi2");
	}
}

输出结果:

InterfaceA---sayHi

InterfaceImpl---sayHi

InterfaceB---sayHi2

注意: 因为在Java中类是单继承的,而接口却是可以多实现的。这样这几的初衷是出于安全性的考虑。因为在多继承的模式中,如果子类C继承了父类A和B,而A和B中又有相同的方法methodAlike。那么这时就无法区分子类C中使用方法时到底是使用哪一父类中的方法了。而(原先的设计)接口则不同,实现类需要实现接口中定义的方法,则不存在上述的安全性问题。

那么,现在的问题是:由于在Java8的新特性中可以在接口中定义非静态的方法,那么当多个接口中定义了相同的非静态default方法时,如果实现类实现了这多个接口时,是不是就出现了多继承了呢?

答案是否定的

这时就会产生编译时错误,需要在实现类中覆盖相同的接口中定义的所有方法方法。

如:

定义接口InterfaceA

package com.jasberyon.java8.interfacer;

public interface InterfaceA {

	public static void sayHi(){
		System.out.println("InterfaceA---sayHi");
	}

	public default void sayHi2(){
		System.out.println("InterfaceA---sayHi2");
	}
}

定义接口InterfaceB

package com.jasberyon.java8.interfacer;

public interface InterfaceB {

	public static void sayHi(){
		System.out.println("InterfaceB---sayHi");
	}

	public default void sayHi2(){
		System.out.println("InterfaceB---sayHi2");
	}
}

那么此时就会发现接口InterfaceA和InterfaceB中有相同的方法:public
defaultvoid
sayHi2(),那么此时实现类就必须去重写相同的方法。

实现类InterfaceImpl

package com.jasberyon.java8.interfacer;

public class InterfaceImpl implements InterfaceA, InterfaceB {

	public static void sayHi(){
		System.out.println("InterfaceImpl---sayHi");
	}

	public void sayHi2(){
		System.out.println("InterfaceB---sayHi2");
	}
}

小结:Java的接口本身就是一种为扩展程序而使用的,在Java8中应该避免让实现类去覆盖具有多个相同default方法的接口,这样没有什么意义。Java8在接口中的新特性仅作为一个扩展而使用。而对于接口中的静态方法,在实现类中去“重写”(实际上不是)是没有意义的。

2. Lambda表达式对匿名内部类的简化使用

Lambda表达式替换了原有的匿名内部类的写法,简化了匿名内部类的使用方式。当然简化的方式总是会使得功能使用时有所限制,Just like 增强型for(for-each)循环。

Lambda表达式的语法结构:

(参数1,参数2...)->{

重写方法内容,不写定义方法名。

}

(1)多线程时使用Lambda表达式

原来的使用匿名内部类实现多线程的栗子:

package com.jasberyon.java8.lambda;

public class ThreadDemo {

	public static void main(String[] args) {

		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i<200; i++){
					System.out.println("执行run---------"+i);
				}

			}
		}).start();

		for(int j=0; j<200; j++){
			System.out.println("执行mian---------------"+j);
		}

	}
}

使用Lambda表达式改造后:

package com.jasberyon.java8.lambda;

public class ThreadDemo {

	public static void main(String[] args) {

		Runnable runnable = ()->{
			for(int i=0; i<200; i++){
				System.out.println("执行run---------"+i);
			}
		};
		new Thread(runnable).start();

		for(int j=0; j<200; j++){
			System.out.println("执行mian---------------"+j);
		}	

	}

}

又或者这样写:

package com.jasberyon.java8.lambda;

public class ThreadDemo {

	public static void main(String[] args) {

		new Thread(()->{
			for(int i=0; i<200; i++){
				System.out.println("执行run---------"+i);
			}
		}).start();

		for(int j=0; j<200; j++){
			System.out.println("执行mian---------------"+j);
		}
	}

}

那么,Lambda的弊端也是显而易见的,如果接口中定义了多个抽象方法,那么就只能使用传统方式了。

(2)集合排序“比较器”中使用Lambda表达式

TreeSet会将字符串按照自然顺序进行排序,如下代码:

package com.jasberyon.java8.lambda;

import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {

	public static void main(String[] args) {

		Set<String> set = new TreeSet<String>();
		set.add("asdafa");
		set.add("abcdefsadf");
		set.add("sahdfoad");
		set.add("bhsayuadasdfasdf");
		set.add("auiweyqwergeawgfasdasd");
		System.out.println(set);
	}

}

结果输出:

[abcdefsadf, asdafa,auiweyqwergeawgfasdasd, bhsayuadasdfasdf, sahdfoad]

使用自定义的比较器后:

package com.jasberyon.java8.lambda;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {

	public static void main(String[] args) {

		Set<String> set = new TreeSet<String>(new MyCompareMethod());
		set.add("asdafa");
		set.add("abcdefsadf");
		set.add("sahdfoad");
		set.add("bhsayuadasdfasdf");
		set.add("auiweyqwergeawgfasdasd");
		System.out.println(set);
	}

}

class MyCompareMethod implements Comparator<String>{

	@Override
	public int compare(String o1, String o2) {
		int length = o1.length() - o2.length();
		return length == 0?o1.compareTo(o2):length;
	}

}

结果输出:

[asdafa, sahdfoad, abcdefsadf,bhsayuadasdfasdf, auiweyqwergeawgfasdasd]

使用匿名内部类后:

package com.jasberyon.java8.lambda;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {

	public static void main(String[] args) {

		Set<String> set = new TreeSet<String>(new Comparator<String>(){
			@Override
			public int compare(String o1, String o2) {
				int length = o1.length() - o2.length();
				return length == 0?o1.compareTo(o2):length;
			}
		});
		set.add("asdafa");
		set.add("abcdefsadf");
		set.add("sahdfoad");
		set.add("bhsayuadasdfasdf");
		set.add("auiweyqwergeawgfasdasd");
		System.out.println(set);
	}

}

使用Lambda表达式改造:

package com.jasberyon.java8.lambda;

import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {

	public static void main(String[] args) {

		Set<String> set = new TreeSet<String>((String o1, String o2)->{
			int length = o1.length() - o2.length();
			return length == 0?o1.compareTo(o2):length;
		});
		set.add("asdafa");
		set.add("abcdefsadf");
		set.add("sahdfoad");
		set.add("bhsayuadasdfasdf");
		set.add("auiweyqwergeawgfasdasd");
		System.out.println(set);
	}

}

也可写成:

package com.jasberyon.java8.lambda;

import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {

	public static void main(String[] args) {

		Set<String> set = new TreeSet<String>((o1, o2)->{
			int length = o1.length() - o2.length();
			return length == 0?o1.compareTo(o2):length;
		});
		set.add("asdafa");
		set.add("abcdefsadf");
		set.add("sahdfoad");
		set.add("bhsayuadasdfasdf");
		set.add("auiweyqwergeawgfasdasd");
		System.out.println(set);
	}

}

值得注意的是,此时需要泛型标注。也就是比较的类型必须在<>中声明,否则无法通过编译。

同时,使用Lambda表达式的实现不会再有额外的类文件(原来的方式匿名内部类也是要产生形如Ttt$xx.class的文件的)产生。

其它的还有很多就不在列举了。记住一点,构造匿名内部类时,如果只有一个方法需要重写,那么就可以使用Lambda表达式。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 04:19:37

Java8新特性小结-接口与Lambda表达式的相关文章

Java8新特性Stream API与Lambda表达式详解(1)

1 为什么需要Stream与Lambda表达式? 1.1  为什么需要Stream Stream作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream.Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggr

Java8新特性学习笔记(一) Lambda表达式

没有用Lambda表达式的写法:  Comparator<Transaction> byYear = new Comparator<Transaction>() {             @Override            public int compare(Transaction o1, Transaction o2) {                return o1.getValue().compareTo(o2.getValue());             

Java8 新特性----函数式接口,以及和Lambda表达式的关系

这里来讲解一下Java8 新特性中的函数式接口, 以及和Lambda 表达式的关系.看到过很多不少介绍Java8特性的文章,都会介绍到函数式接口和lambda表达式,但是都是分别介绍,没有将两者的关系说明清楚,在这里,把自己的理解整理如下: 一.函数式接口: 函数式接口其实本质上还是一个接口,但是它是一种特殊的接口:SAM类型的接口(Single Abstract Method).定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个lambda表达式作为参数.从另一个方面说,一旦我

java8新特性(二)_lambda表达式

最近一直找java8相关新特性的文章,发现都太没有一个连贯性,毕竟大家写博客肯定都有自己的侧重点,这里找到一本书,专门介绍java8新特性的,感觉大家可以看看<写给大忙人看的JavaSE8>.这里我会结合书中的知识以及网上的知识,对于java8 的新特性进行总结,当然我自己写的也会有自己的侧重点. java8为什么增加了函数式编程 java作为一门面向对象的编程语言诞生于20世纪90年代.在当时,面向对象编程是软件开发的主流模式. 由于最近在并发和事件驱动(或者称为“互动”)编程中的优势,函数

java8新特性——函数式接口,方法,构造器,数组引用

package functional; /* 定义:如果一个接口里面只声明了一个函数,就称为函数式接口 lambda表达式的本质:作为函数式接口的实例,必须依赖一类特别的对象类型——函数式接口 所以用匿名实现类表示的都可以用lambda表达式来写 Java.util.function 下也定义了Java8的函数式接口 函数式接口 内置抽象类 作用 1.Consumer<T>: void accept(T t) 消费型 2.Supplier<T>: T get() 返回一个对应的T对

java8新增特性(一)---Lambda表达式

Lambda表达式也成为闭包,是java语言层次上的改变,Lambda同意把函数作为一个方法的參数(函数作为參数传递进方法中),或者把代码看成数据.函数式程序猿对这一概念非常熟悉. 在JVM平台上有非常多语言(groovy,scala等等)从一開始就有Lambda,可是程序猿不得不使用匿名类来取代lambda. 看一下jdk7之前实现字符串排序: package com.panther.dong.java8.lambda; import java.util.Arrays; import java

Java8新特性:接口

Java接口本身没有任何实现,因为Java接口不涉及表象,而只描述public行为,所以Java接口比Java抽象类更抽象化. 以上是百度百科中对接口的定义,这个定义已经不准确. Java8对接口做了进一步的增强.1.在接口中可以添加使用 default 关键字修饰的非抽象方法. 2.接口里可以声明静态方法.interface名.静态方法名()直接时候用.(暴力吧) //定义一个接口,有三个方法. public interface IfTestIf {  public static void d

【Java学习笔记之二十八】深入了解Java8新特性

前言: Java8 已经发布很久了,很多报道表明java8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java 8 – Lambdas and Concurrency.Java 8 Date Time API Tutorial : LocalDateTime和Abstract Class Versus Interface in the JDK 8 Era.本文还参考了一些其他资料,例如:15 Must Read

Java8新特性分享

原文地址:http://www.importnew.com/19345.html |放在下面防止网站挂了..做个备份 1.简介 毫无疑问,Java 8是自Java  5(2004年)发布以来Java语言最大的一次版本升级,Java 8带来了很多的新特性,比如编译器.类库.开发工具和JVM(Java虚拟机).在这篇教程中我们将会学习这些新特性,并通过真实例子演示说明它们适用的场景. 本教程由下面几部分组成,它们分别涉及到Java平台某一特定方面的内容: 语言 编译器 类库 开发工具 运行时(Jav