JavaEE-JDK8新特性

Java新特性

Java8接口新特性

概述

  1. java8中的接口,不仅能定义抽象方法,还能定义非抽象方法
  2. 抽象方法定义方式和之前的一样。默认加上public abstract,不能拥有方法体的。连大括号都没有
  3. 非抽象方法拥有方法体,必须使用默认default或者static修饰

Default

  1. 使用原因:
    • 为了增加List接口的功能,如果增加抽象方法,那么所有实现List接口的实现类都要将新增的抽象方法进行实现,结果就可能导致原来的旧的项目无法编译通过。新增的方法,就加上了默认的实现,但是这种默认的实现不会强制要求实现类进行重写。
  2. 使用规则:
    1. 加上default,实现类可以不重写,直接调用
    2. 特殊情况:实现类实现了两个接口,如果有相同的方法的默认方法,则强制要求在实现类中重写这个方法,以确定实现的内容
      • 如果实现类在重写的过程中,就想指定其中某个接口的默认方法的实现的时候,此时可以使用接口名.super.默认方法名()的格式,指定 想要在实现类中重写后实现的接口中的默认方法
    3. 特殊情况:实现类在继承一个类的前提下,又实现了一个接口,在父类中和接口中出现相同的方法的声明的时候,采用“类优先”,在实现类 中不需要再对该方法进行重写
  3. 产生影响:
    1. 接口中如果也可以定义非抽象方法,那么接口和抽象类的差距就越来越小了。
    2. java中一个类只能继承一个类的,但是可以实现多个接口。
    3. 有了默认方法,抽象类地位就越来越弱。

static

  1. 接口的静态方法可以定义方法实现的内容的
  2. 静态方法不能被抽象
  3. 外界只能通过接口名称.静态方法来访问接口中的静态方法,实现类中不会继承接口中的静态方法
    • 如果一个类同时实现了两个接口,具有相同的静态方法签名,继承之后不知道以哪个为准
package com.danny.interstatic;

public interface Inter {
	void inter() ;
	static void show() {
		System.out.println("静态的抽象方法");
	}
}
package com.danny.interstatic;

public class InterImpl implements Inter {
	@Override
	public void inter() {
		System.out.println("inter方法");
	}
}
package com.danny.interstatic;

public class Test {
	public static void main(String[] args) {
		Inter.show();
		InterImpl impl = new InterImpl();
	}
}

二. Lambda表达式

概述

  1. 本质:
    • 表示一个对象,指定接口的实现类对象
  2. 前提:
    • 接口必须是函数式接口,只能有一个抽象方法的接口
  3. 好处:
    • 匿名内部类的格式的一种简写,可以间接表示一个方法实现的逻辑。可以提升开发效率

格式详解

  1. 格式:
    • 函数式接口名 对象名 = (参数列表)->{方法体};
  2. 详细说明:
    • 函数式接口名:接口名称(接口中的抽象方法只能有一个)
    • 对象名:合法的标识符即可
    • (参数列表):表示的是要实现的接口中,抽象方法的参数
    • ->:箭头运算符,或者称为lambda,运算符,用于分隔前后两部分
    • 方法体:也称为lambda体,表示对抽象方法重写的内容
  3. 语法格式:
    1. 没有参数,没有返回值
      • ()->{方法体};
      • 方法体如果是一条语句,此时可以省略大括号
      • eg:()->System.out.println(“内容”);
    2. 有一个参数,没有返回值
      • (参数)->{方法体};
      • 参数列表中的数据类型可以省略不写的,甚至连变量的名称都能和抽象方法中的不一样
      • 如果参数只有一个的时候,可以省略小括号的
      • eg: m -> System.out.println(m);
    3. 有多个参数,有返回值
      • (参数1,参数2,…)->{方法体};
      • 简写格式:
        • 针对的是lambda体只有一句,且有返回值,此时return和大括号可以一起省略
        • eg:(x,y)->{return x + y} 等价于 (x,y)-> x + y;
package com.danny.lambda;

public class Demo_1 {
	public static void main(String[] args) {
//		lambda表达式
//		匿名内部类实现
//		有多个参数,有返回值
		/*Inter_3 i3 = new Inter_3() {
			@Override
			public int show(int x, int y) {
				int sum = x + y;
				return sum;
			}
		};
		int show = i3.show(23, 34);
		System.out.println(show);*/
//		使用lambda表达式
		Inter_3 i33 = (x, y) -> {
//			int sum = x + y;
//			return sum;
			System.out.println(y.length());
			return x + y;
		};
		String show = i33.show(100, "java");
		System.out.println(show);
//		简写格式:针对的是lambda体只有一句,且有返回值,此时return和大括号可以一起省略
		Inter_3 i333 = (x, y) -> x + y;
		String show1 = i333.show(200, "hello");
		System.out.println(show1);
	}

	private static void test_2() {
		// 有一个参数,没有返回值
		Inter_2 i2 = new Inter_2() {
			@Override
			public void show(int x) {
				System.out.println(x);
			}
		};
		i2.show(100);
		// lambda表达式实现
		Inter_2 i22 = (int x) -> {
			System.out.println(x);
		};
		i22.show(999);
		// 简写格式:
		// 参数列表中的数据类型可以省略不写的,甚至连变量的名称都能和抽象方法中的不一样
		// 如果参数只有一个的时候,可以省略小括号的
		Inter_2 i33 = m -> System.out.println(m);
		i33.show(888);
	}

	private static void test_1() {
		// 无参,无返回值
		Inter_1 i1 = new Inter_1() {

			@Override
			public void show() {
				System.out.println("匿名内部类实现的");
			}

		};
		i1.show();
		// 使用lambda表达式实现
		Inter_1 i11 = () -> {
			// 对接口中抽象方法的具体实现
			System.out.println("lambda表达式实现的");
		};
		i11.show();

		// 简写格式:方法体如果是一条语句,此时可以省略大括号
		Inter_1 i111 = () -> System.out.println("lambda表达式简写格式");
		// 对接口中抽象方法的具体实现

		i111.show();
	}
}

//函数式接口
interface Inter_1 {
//	无参,无返回值的抽象方法
	void show();
}

interface Inter_2 {
//有一个参数,没有返回值
	void show(int x);
}

interface Inter_3 {
	// 有多个参数,有返回值
	String show(int x, String y);
}

三. 函数式接口

  1. 函数式接口是lambda表达式的前提
  2. 定义:
    • 如果在一个接口中,只有一个抽象方法的声明,那么这个接口就是函数式接口
  3. 格式说明;
    • 使用注解来检查接口是否是一个函数式接口
    • @FunctionalInterface
    • 如果不是函数式接口,就会编译报错
  4. 理解:
    • 函数:想表达的是一个方法的内容,由于方法不再任何类中,所以称为函数
    • 函数式接口:其实想表达的是一个函数的声明
  5. 作用:
    • 使用函数式接口表达函数的声明:使用函数式接口的实现类表达函数的实现
  6. 使用原因:
    • java中不支持将函数作为一个数据,也就不能将这个函数进行传递,也就不能作为一个对象的成员而存在
    • 只有在方法的外面加一层接口的声明,将来可以传递方法所在接口的实现类对象,来间接的传递方法的实现逻辑
package com.danny.lambda;

public class Demo_2 {
	public static void main(String[] args) {
//		函数式接口
		int b = 10;
//		调用test方法的时候,传递的实参是test方法中形式参数的一个实现类对象
//		InterFun_1 i1 = ()->System.out.println("test");
	
//		InterFun_1 i1 = new InterFun_1() {
//			@Override
//			public void show() {
//				System.out.println("test");
//			}
//		};
		
		InterFun_1 i1 = ()->System.out.println("test");
		InterFun_1 i2 = ()->{
			System.out.println("test");
			System.out.println("i2");
		};
//		test(i2);
		test(()->System.out.println("test"));
	}
	
	public static void test(InterFun_1 i1) { //InterFun_1 i1 = i1;
		i1.show();
	}
}

@FunctionalInterface
interface InterFun_1{
	void show();
}

常用的内置型函数式接口

  1. java8中提供了一些常用的内置型函数式接口,在使用类似功能的时候,就不需要自己再去定义了,而是直接使用内置型函数式接口即可。
  2. 罗列:
    • Consumer<T> :消费型接口
      • void accept(T t);
    • Supplier<T> : 供给型接口
      • T get();
    • Function<T,R>:函数型接口
      • R apply(T t);
    • Predicate<T>:断言型接口
      • boolean test(T t)

消费型接口

  1. Consumer<T>
  2. 消费型接口
  3. 抽象方法
    • void accept(T t);
  4. 作用:
    • 当某个函数可以接收一个数据,并且处理这个数据,处理完之后,不需要返回任何数据的时候,这个函数(处理数据的逻辑)当做数据进行传递的时候,就可以使用消费型接口了
    • 以前只能传递要处理的数据,现在可以传递处理数据的逻辑
package com.danny.functioninter;

import java.util.function.Consumer;

public class Demo_1 {
//	消费型接口
	public static void main(String[] args) {
		test("java");
		
		Consumer<String> con = (t)->{
			String substring = t.substring(0,2);
			System.out.println(substring);
		};
		
		Consumer<String> con1 = (t)->{
			char c = t.charAt(0);
			System.out.println(c);
		};
		
		testCon("中国成都",con1);//在调用方法的时候,要传递对数据处理的逻辑
	}
	
	public static void testCon(String str,Consumer<String> con) {
		con.accept(str);//定义方法的时候,不知道要对str进行怎样的处理
	}
	
	
	public static void test(String str) {//传递的就是数据
		int length = str.length();//在定义方法的时候,就将对数据str处理的方式(逻辑)已经定义好了
		System.out.println(length);
	}
	
}


//interface Inter{
//	void test(int t);
//}

方法引用

  1. 写一个函数式接口时,方法的实现(lambda体),已经被其他的某个对象实现了,就不需要再lambda体中,将该方法再次实现,而是可以直接借用一下已经在其他对象中对该方法的实现。直接调用,直接使用其他对象中已经定义好的方法。
  2. 格式:
    • 函数式接口 名称 = 对象名::方法名称;
    • 函数式接口 名称 = 类名 :: 静态方法名;
  3. 作用:
    • 把已经实现的方法,作为一个数据,作为实现类的对象,赋值给函数式接口的引用。
    • 可以把这个引用当做方法的返回值,也可以作为方法的实际参数进行传递
  4. 本质:
    • 可以把任意一个方法,作为函数式接口的一个实现类对象
package com.danny.functioninter;

public class Demo_2 {
	public static void main(String[] args) {
//		方法引用
//		FunInter_1 f1 = (x,y)->System.out.println(x + y);
//		f1.printSum(123, 90);
		Method m = new Method();
//		使用方法引用,借用m对象中的方法的实现
//		函数式接口 名称 = 对象名::方法名称;
		FunInter_1 f1 = m :: test_1;
		f1.printSum(200, 300);
		
		test(m :: test_1);//方法引用作为一个参数进行传递
		
		
//		FunInter_2 f2 = (str)->System.out.println(str);
		FunInter_2 f2 = System.out::println;
		f2.print("java");
	}
	
	public static void test(FunInter_1 f1) {//FunInter_1 f1 = m :: test_1;
		f1.printSum(900, 100);
	}
}

class Method{
	public void test_1(int x,int y) {
		
		System.out.println(x + y + "Method");
	}
}

interface FunInter_1{
	void printSum(int x,int y);
} 

interface FunInter_2{
	void print(String str);
}

供给型接口

  1. Supplier<T>
  2. 供给型接口
  3. 抽象方法
    • T get();
  4. 作用:
    • 如果定义一个函数(方法的实现的逻辑),可以生产一个需要的数据,这个函数需要作为一个数据进行传递,就可以使用此接口
    • 以前我们只能传递数据,可以传递生产数据的逻辑
package com.danny.functioninter;

import java.util.Random;
import java.util.function.Supplier;

public class Demo_3 {
	public static void main(String[] args) {
//		Supplier<T> : 供给型接口
		Supplier<Integer> sup = ()->{
			return 1;
		};
		
		Supplier<Integer> sup1 = ()->{
			Random ran = new Random();
			int nextInt = ran.nextInt(99);
			return nextInt;
		};
		
		int num = getNum(sup1);//在方法调用的时候,传递生产数据的方式,得到一个数据
		System.out.println(num);
		
		
	}
	
	public static int getNum(Supplier<Integer> sup) {
		return sup.get();//在方法的定义中,不知道要会返回数据是一个什么样的数据
	}
	
	
	public static int getNum() {
//		方法在定义的过程中,就将返回数据的逻辑定义好了
		Random ran = new Random();
		int nextInt = ran.nextInt(99);
		return nextInt;
	}
}

函数型接口

  1. Function<T,R>
  2. 函数型接口
  3. 抽象方法
    • R apply(T t)
  4. 作用:
    • 如果需要定义一个函数,接口一个数据,将数据进行处理,处理完之后进行返回,可以使用函数型接口
    • 以前我们只能传递要处理的数据,现在可以传递处理数据的逻辑
  5. 提供功能
    • andThen(Function<T,R> fun)
    • 在调用者处理方式之后,再将调用者处理的结果作为fun的参数,再次进行处理
package com.danny.functioninter;

import java.util.function.Function;

public class Demo_4 {
	public static void main(String[] args) {
//		函数型接口
		int dealData = dealData("I love java");
		System.out.println(dealData);
		
		Function<String, Integer> fun = t -> {
			int indexOf = t.indexOf("o");
			return indexOf;
		};
		
		
		Function<String, Integer> fun1 = t -> t.length();
		
		int dealData2 = dealData("I love java",fun1);
		System.out.println(dealData2);
//		--------------------------------------------
//		andThen方法
		Function<String, Integer> fun11 = t -> t.length();
		Function<Integer, String> fun2 = t -> "处理之后的结果:" + t;
		
		String dealData3 = dealData("I love java",fun11,fun2);
		System.out.println(dealData3);
	}
	
	public static String dealData(String str,Function<String,Integer> fun1,Function<Integer,String> fun2) {
//		Integer apply = fun1.apply(str);//将一个String类型的数据进行处理,得到一个int类型的值
//		
//		String apply2 = fun2.apply(apply);//将一个integer类型的数据进行处理,得到一个String类型的值
		String apply = fun1.andThen(fun2).apply(str);//等价于上面的执行过程
		return apply;	
	}
	public static int dealData(String str,Function<String,Integer> fun) {
//		将处理数据的逻辑进行一个传递,在定义方法的时候,不知道要对数据str进行怎么样的处理
//		知道的是,要处理的数据是str。处理之后的结果是Integer类型
		Integer apply = fun.apply(str);
		return apply;
	}
	public static int dealData(String str) {
//		在方法的定义中,就将处理数据str的方式定义好了
		int length = str.length();
		return length;
	}
}

断言型接口

  1. Predicate<T>
  2. 断言型接口
  3. 抽象方法
    • boolean test(T t)
  4. 作用:
    • 如果需要定义一个函数,接口一个数据,判断数据是否合法,返回一个boolean类型的结果,此时就可以使用断言型接口
    • 以前只能定义判断数据的逻辑,现在可以传递判断数据的逻辑
  5. 提供的方法:
    • and(Predicate pre):在调用者判断之后,再由参数pre进行判断,返回两个对象都满足的内容
    • or(Predicate pre):在调用者判断之后,再由参数pre进行判断,返回两个对象满足其一的结果
    • negate():返回调用者判断条件的取反
package com.danny.functioninter;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class Demo_5 {
	public static void main(String[] args) {
//		断言型接口
		Predicate<String> pre = t -> {
//			写上对数据处理的逻辑
			boolean startsWith = t.startsWith("大");
			return startsWith;
		};

		boolean right = isRight("大熊猫", pre);// 在方法调用的时候,才知道具体对数据出来的方式(逻辑)
		System.out.println(right);
//		------------------------------------------------------
		System.out.println("------------------------------");
		List<String> list = new ArrayList<String>();
		list.add("肖战");
		list.add("王一博");
		list.add("蔡徐坤");
		list.add("马保国");
		list.add("马云");
		list.add("迪丽热巴");
		System.out.println(list);
		Predicate<String> pre1 = t -> t.length() == 3;
		Predicate<String> pre2 = t -> t.length() == 4;
		List<String> newList = getNewList(list, pre2);
		System.out.println(newList);
//		and方法---------------------------------------------------------------------------------------------
		Predicate<String> pre11 = t -> t.length() == 3;
		Predicate<String> pre22 = t -> t.startsWith("马");
		List<String> newList2 = getNewList(list, pre11, pre22);
		System.out.println(newList2);
	}

//	and or,negate方法
	public static List<String> getNewList(List<String> list, Predicate<String> pre1, Predicate<String> pre2) {
//		创建一个新的集合,用来存储筛选后的数据
		ArrayList<String> newList = new ArrayList<String>();
		for (String string : list) {
//			if(pre1.test(string) && pre2.test(string)) {
//			if (pre1.and(pre2).test(string)) {
//			if (pre1.or(pre2).test(string)) { // or方法
			if (pre1.negate().test(string)) {// negate方法
				newList.add(string);
			}
		}
		return newList;
	}

	public static List<String> getNewList(List<String> list, Predicate<String> pre) {
//		创建一个新的集合,用来存储筛选后的数据
		ArrayList<String> newList = new ArrayList<String>();
		for (String string : list) {
			if (pre.test(string)) {// 满足了test方法判断的结果之后,才能添加到新集合中
				newList.add(string);
			}
		}
		return newList;
	}

	public static boolean isRight(String str, Predicate<String> pre) {
//		定义方法期间,完成对str的操作,但是对数据str进行怎么样的判断,不确定的
		boolean test = pre.test(str);
		return test;
	}

	public static boolean isRight(String str) {
//	 	在方法定义的时候,就将判断数据str的方式已经定义好了
		if (str.length() >= 3) {
			return true;

		} else {
			return false;
		}
	}
}

四. Stream

概述

  1. 在java1.8中,提供了一个Stream类型,可以对数据进行过滤
  2. 好处:
    • 比不断的定义循环,遍历数据,要简单很多

Stream类型的获取

  1. Collection的获取
    • 调用stream()方法即可,返回Stream类型的对象
  2. Map的获取:不能直接获取Stream类型
    1. keySet().stream();
    2. entrySet().stream();
    3. values().stream();
  3. 数组的获取
    • static of(T… values) 可变参数
package com.danny.stream;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Stream;

public class Demo_1 {
//	stream
	public static void main(String[] args) {
		
//		Collection集合的获取
		Collection<String> coll = new ArrayList<String>();
		Stream<String> stream = coll.stream();//将容器的数据,放入了一个数据流中。
//		Map的获取
		Map<String,Integer> map = new HashMap<>();
//		(1)keySet().stream();
		Set<String> keySet = map.keySet();
		Stream<String> stream2 = keySet.stream();
//		(2)entrySet().stream();
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		Stream<Entry<String, Integer>> stream3 = entrySet.stream();
//		(3)values().stream();
		Collection<Integer> values = map.values();
		values.stream();
//		数组的获取
		Integer[] arr = {1,2,3,4,5};
		Stream<Integer> of = Stream.of(arr);
		
		sum(1,2,3,4,4,5,3,3,2,32,32,323,23,2,32,323);
	}
	
	public static void sum(int... d) {//int[] d
		for(int i = 0;i<d.length;i++) {
			System.out.println(d[i]);
		}
	}
}

Stream中常用的方法

  1. 常用方法:用于对获取到的数据流对象进行数据的处理。可以筛选,可以转型,可以过滤
  2. 分类:
    1. 终结方法:调用完之后,返回值不在是Stream类型本身,无法继续调用Stream中的方法
      • eg:forEach,count
    2. 延迟方法:调用完之后,返回值还是一个Stream类型,可以继续调用Stream中的方法
      • eg:limit,skip,filter,map
  3. 罗列:
    • Stream<T> filter(Predicate<T> pre)
      • 根据pre的判断条件,会对流中的数据进行过滤
    • forEach(Consumer<? super T> con)
      • 将流中的数据,按照指定con描述对数据的处理方式,进行处理
    • Stream<T> limit(long maxSize)
      • 根据参数maxSize描述的个数,对流中的数据进行截取
    • Stream<T> skip(long n)
      • 根据参数n描述的个数,跳过参数n的个数的数据,流中剩余的就是n之后的内容
    • Stream<R> map(Function<T,R> fun)
      • 将流中所有T类型的数据,都根据fun这个函数型接口,转换成其他R类型的数据
    • Stream<R> count();
      • 获取流中所有的数据的个数
    • static Stream<R> concat(Stream<? extends T> a,Stream<? extends T> b)
      • 可以将a和b这个两个流,合并为一个流
package com.danny.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class Demo_2 {
	public static void main(String[] args) {
//		常用方法
		List<String> list = new ArrayList<>();
		list.add("宫本武藏");
		list.add("上官婉儿");
		list.add("不知火舞");
		list.add("孙悟空");
		list.add("猪八戒");
		list.add("达摩");
		list.add("鲁班");
		System.out.println(list);
//		调用stream方法获取该集合的一个Stream类型的对象
		Stream<String> stream = list.stream();
//		Stream<T> filter(Predicate<T> pre)
//		根据pre的判断条件,会对流中的数据进行过滤
		/*		Predicate<String> pre = x -> x.length() == 4;
				Stream<String> filter = stream.filter(pre);
		//		foreach(Consumer<T> con)
				Consumer<String> con = x -> System.out.println(x);
				filter.forEach(con);*/
		stream.filter(x -> x.length() == 4).filter(x -> x.startsWith("不")).forEach(x -> System.out.println(x));

//		Stream<T> limit(long maxSize)
		System.out.println("---------limit(long maxSize)-----------");
		Stream<String> stream2 = list.stream();
		stream2.limit(4).forEach(System.out::println);
//		//		Stream<T> skip(long maxSize)
		System.out.println("---------skip(long maxSize)-----------");
		Stream<String> stream3 = list.stream();
		stream3.skip(4).forEach(System.out::println);
//		Stream<R> map(Function<T,R> fun)
		System.out.println("---------Stream<R> map(Function<T,R> fun)-----------");
		Stream<String> stream4 = list.stream();
		Function<String, Integer> fun = x -> {return  x.length();};
		stream4.map(fun).forEach(System.out::println);
//		count();获取流中所有的数据的个数
		System.out.println("---------count)-----------");
		Stream<String> stream5 = list.stream();
		long count = stream5.count();
		System.out.println(count);
//		static Stream<R> concat(Stream<? extends T> a, Stream<? extends T> b) 
		System.out.println("--------concat()-----------");
		Stream<String> stream6 = list.stream();
		Stream<String> filter1 = stream6.filter(x->x.length()==4);
//		filter1.forEach(System.out::println);
		
		Stream<String> stream7 = list.stream();
		Stream<String> filter2 = stream7.filter(x->x.length()==2);
//		filter2.forEach(System.out::println);
		Stream<String> concat = Stream.concat(filter1,filter2);
		concat.forEach(System.out::println);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值