java8新特性

1.Lambda表达式

2.函数式接口

3.Stream API

 

一、Lambda表达式

1.引入

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		
		test();
		
	}

	private static void test() {
		MyInter mi = new MyInter() {
			@Override
			public void test() {
				System.out.println("test方法被调用了");
			}
		};
		mi.test();//test方法被调用了
	}
	
}
interface MyInter{
	void test();
}

       本着“万物皆对象”的思想,创建一个MyInter接口的内部类对象来指定内容,再调用方法,这种做法是OK的。但是……

       我们真的想创建一个匿名内部类对象吗?

       不。我们只是为了做这件事情而不得不创建一个对象。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。

       那,有没有更加简单的办法?

       如果我们将关注点从“怎么做”回归到“做什么”的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要。

2.Lambda语法和使用

      Lambda表达式就是对匿名内部类对象的一种格式的简化。

      Java8中引入了一个新的操作符“->”,称为箭头运算符,或者Lambda运算符

      作用:就是用于分隔前后两部分的:

      左边:表示Lambda表达式的参数列表(接口中,定义的抽象方法的参数)

      右边:表示的是方法的方法体,Lambda体

      语法格式1:没有参数,也没有返回值

      () -> System.out.println(“test方法被调用了”);

      代码示例

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		
		test();
		
	}

	private static void test() {
		MyInter mi = ()->System.out.println("第一种格式:test方法被调用了");
		mi.test();	
	}
	
}
interface MyInter{
	void test();
}

      语法格式2:有一个参数,没有返回值

      :如果只有一个参数,那么小括号可以省略

      (x) -> System.out.println(x * x);

      代码示例

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		
		test();	
	}

	private static void test() {
		MyInter mi1 = (x)->System.out.println(x*x);
		mi1.test(3);
		
		//如果只有一个参数的时候,小括号可以省略不写
		MyInter mi2 = y->System.out.println(y*y);
		mi2.test(3);
	}
	
}
interface MyInter{
	void test(int x);
}

      语法格式3:有多个参数,没有返回值,格式和语法格式和2相同

      (x, y) -> System.out.println(x + y);

      代码示例

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		
		test();	
	}

	private static void test() {
		MyInter mi = (m,n)->System.out.println(m+n);
		mi.test(1, 2);
	}
	
}
interface MyInter{
	void test(int x,int y);
}

      语法格式4:接口中需要重写的方法,方法内容有多句,需要给多句加上大括号

      (x, y) -> {int result = x + y; return result;}

      :如果Lambda体中语句只有一句,那么大括号也可以省略不写;如果大括号中只有一条语句,并且是return语句,那么return关键字也可以省略不写(如果要省略return关键字,就必须省略大括号)。

      例如:(x,y)->x+y

      代码示例

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		
		test();	
	}

	private static void test() {
		
		MyInter mi1 = (m,n)->{
			int sum=m+n;
			return sum;
		};
		int sum = mi1.test(1, 2);
		System.out.println("sum="+sum);
		
		
		MyInter mi2 = (m,n)->{
			return m+n;
		};
		System.out.println(mi2.test(2, 3));
		
		
		//如果只有一句话,可以省略大括号,如果是return语句,就可以把return关键字省略掉
		MyInter mi3 = (m,n)->m+n;
		System.out.println(mi3.test(3, 4));
		
	}
	
}
interface MyInter{
	int test(int x,int y);
}

二、函数式接口

1、概述

        Lambda表达式使用的前提,就是接口必须是一个函数式接口。

        定义:如果在接口中,只有一个抽象方法,那么这个接口就是函数式接口。

        格式:使用注解来检查当前接口是否是一个函数式接口。

        @FunctionalInterface

        如果不是函数式接口,则编译报错。

        作用

        想表达的是一个方法的内容,由于方法不在任何类中,所以称为函数。

        接口其实想表达的就是一个函数的声明。

        将来使用这个接口的实现类对象,来表达一个函数的实现。

        Java中不支持将函数作为一个数据,也就不能将这个函数进行各种传递,也就不能作为对象的成员变量存在。

        只能在方法外加一层接口的声明,将来可以传递方法所在接口的实现类对象,来间接的传递方法内容。

        函数和方法的区别:函数式独立存在的,不存在任何一个类中;方法是存在一个类中。

        代码示例

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		
		Inter1 i = new Inter1(){
			public void test1(){
				System.out.println("hello");
			}
		};
	}
	
	// Inter1的对象作为参数
	public static void method1(Inter1 i){
		i.test1();
	}
	
	//Inter1的对象作为返回值
	public static Inter1 method2(){
	   /*	
		Inter1 i = new Inter1(){
			public void test1(){
				System.out.println("hello");
			}
		};
		*/
		Inter1 i = ()->System.out.println("hello");
		return i;
	}
}
@FunctionalInterface
interface Inter1{
	void test1();
}

/*@FunctionalInterface
interface Inter2{//没有方法  报错
					
}

@FunctionalInterface
interface Inter3{//有多个方法  报错
	void test1();
	void test2();
}
*/

2.常用内置函数式接口

         Java8中提供了一些常用的函数式接口,在使用类似功能的时候,不需要额外定义接口,直接使用jdk中提供的即可。

函数式接口

参数类型

返回类型

说明

Consumer<T>

消费型接口

T

void

对类型为T的对象操作,

方法:void accept(T t)

Supplier<T>

供给型接口

T

返回类型为T的对象,

方法:T get();可用作工厂

Function<T, R>

函数型接口

T

R

对类型为T的对象操作,并返回结果是R类型的对象。

方法:R apply(T t);

Predicate<T>

断言型接口

T

boolean

判断类型为T的对象是否满足条件,并返回boolean 值。

方法boolean test(T t);

     (1)消费型接口Consumer<T>

      抽象方法:void accept(T t);

      作用:当某个函数可以接收一个数据,并且处理这个数据,处理完成之后,不需要返回任何数据,这个函数需要当做数据来进行传递,就使用消费型接口。

     代码示例

package com.xj.Test;

import java.util.function.Consumer;

class Test {
	public static void main(String[] args) {
		
	/*Consumer<String> con = new Consumer<String>() {
		public void accept(String str) {
			System.out.println(str);
		}
	};
	test(con,800,"买书");*/
	
	Consumer<String> con = (str)->System.out.println(str);
	test(con,800,"买书");
	
	}
	public static void test(Consumer<String> con,int money,String str) {
		System.out.println("花了"+money+"块钱");
		con.accept(str);
	}
	
}

     (2)方法引用

       写一个函数式接口时,方法的实现(lambda体),已经被某个其他的对象实现了,就不需要在Lambda体中,再次调用这个实现,而可以直接使用那个已经定义好的方法。

      格式

      函数式接口 名称 = 对象名 :: 方法名称

      函数式接口 名称 = 类名 :: 静态方法名

      作用

      把已经实现的方法,作为一个数据,作为一个引用,赋值给某个函数式接口的引用。

      可以把这个引用当做方法的返回值,也可以作为方法的实际参数进行传递。

      本质

      可以把任意一个方法,作为函数式接口的一个实现类对象。

package com.xj.Test;

class Test {
	public static void main(String[] args) {
		test01();	
	}

	private static void test01() {
		/*PrinterString ps = x->System.out.println(x);
		ps.print("zxc");*/
		
		PrinterString ps2 = System.out::println;
		ps2.print("方法的引用");		
	}
	
	
}

interface PrinterString {
	abstract void print(String str);
}

     (3)供给型接口Supplier<T>

       抽象方法:T get()

       作用

       如果需要定义函数,可以生产一个需要的数据,这个函数需要当做数据来进行传递,那么就可以使用供给型接口。

       以前我们只能传递数据,现在可以传递生产数据的方式。

       代码示例:返回一集合,集合存放30-80之间的随机数

package com.xj.Test;

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

class Test {
	public static void main(String[] args) {
		
		Random r = new Random();
		List<Integer> list = getNum(10,()->r.nextInt(51)+30);
		System.out.println(list);
	}

	private static List<Integer> getNum(int n, Supplier<Integer> sup) {
		List<Integer> list = new ArrayList();
		for(int i=0;i<n;i++) {
			list.add(sup.get());
		}
		return list;
	}	
	
}

     (4)Function<T, R>

       抽象方法:R apply(T t)

       作用

       如果需要定义一个函数,接收一个数据,将数据进行处理,完成之后,还能返回一个结果,就可以使用函数型接口。

      以前我们只能传递处理好之后的数据,或者将原始数据传入方法。

      现在可以传入原始数据,并且还可以传入处理方式。

      提供功能:andThen(Function f):在调用者处理方式之后,再进行参数的处理方式处理。

      代码示例

package com.xj.Test;

import java.util.function.Function;

class Test {
	public static void main(String[] args) {
		
		//Function<String,Integer> fun = x->Integer.parseInt(x);
		Function<String,Integer> fun = Integer::parseInt;
		int x = parse("20",fun);
		System.out.println(x);
		
		Function<Integer,Integer> fun1 = y-> y*=10;
		int result = method(5,fun1);
		System.out.println(result);
		
		System.out.println(method01("7",fun,fun1));//70  传入一个String的变量, 把字符串转换成数字,并乘10
		
	}
	public static int parse(String str,Function<String,Integer> fun) {
		return fun.apply(str);
	}
	
	public static int method(int i,Function<Integer,Integer> fun) {
		return fun.apply(i);
	}
	
	public static int method01(String str,Function<String,Integer> fun1,Function<Integer,Integer> fun2) {
		return fun1.andThen(fun2).apply(str);
	}
}

     (5)断言型接口Predicate<T>

      抽象方法:boolean test(T t)

     作用:

     如果需要定义一个函数,接收一个数据,判断数据是否合法,返回一个boolean结果,就可以使用断言型接口。

     以前我们只能传入处理好的数据,到方法中。

     将原始数据传入,将过滤的条件也传入。

    提供的功能:

default Predicate<T>

and(Predicate<? super T> other) 

返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND。

default Predicate<T>

or(Predicate<? super T> other) 

返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或。

default Predicate<T>

negate() 

返回表示此谓词的逻辑否定的谓词。

boolean

test(T t) 

在给定的参数上评估这个谓词。

      代码示例

package com.xj.Test;

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

class Test {
	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList<>();
		list.add(10);
		list.add(23);
		list.add(34);
		list.add(35);
		list.add(43);
		list.add(20);
		list.add(50);
		list.add(31);
		list.add(-30);
		list.add(0);

		// 过滤list留下偶数
		List<Integer> list1 = filterEven(list, (x) -> x % 2 == 0);
		System.out.println(list1);

		// 过滤list留下正数
		List<Integer> list2 = filterZheng(list, (x) -> x > 0);
		System.out.println(list2);

		// 使用and连接两个Predicate
		List<Integer> list3 = filterEvenAndZheng(list, (x) -> x % 2 == 0, (x) -> x > 0);
		System.out.println(list3);
		
		//使用or连接两个Predicate
		List<Integer> list4 = filterEvenOrZheng(list,(x) -> x % 2==0, (x) -> x > 0);
		System.out.println(list4);
		
		//取反negate
		List<Integer> list5 = filterEvenNeg(list,(x) -> x % 2 == 0);
		System.out.println(list5);
		
	}


	// 过滤list留下偶数
	public static List<Integer> filterEven(List<Integer> list,Predicate<Integer> pre){
		List<Integer> result = new ArrayList<Integer>();
		for(Integer x:list) {
			if(pre.test(x)) {
				result.add(x);
			}
		}
		return result;
	}

	// 过滤list留下正数
	public static List<Integer> filterZheng(List<Integer> list, Predicate<Integer> pre) {
		List<Integer> result = new ArrayList<Integer>();
		for (Integer x : list) {
			if (pre.test(x)) {
				result.add(x);
			}
		}
		return result;
	}

	// 使用and连接两个Predicate
	public static List<Integer> filterEvenAndZheng(List<Integer> list, Predicate<Integer> pre1,Predicate<Integer> pre2) {
		List<Integer> result = new ArrayList<Integer>();
		for (Integer x : list) {
			if (pre1.and(pre2).test(x)) {
				result.add(x);
			}
		}
		return result;
	}
	
	//使用or连接两个Predicate
	public static List<Integer> filterEvenOrZheng(List<Integer> list,Predicate<Integer> pre1,Predicate<Integer> pre2){
		List<Integer> result = new ArrayList<Integer>();
		for(Integer x:list) {
			if(pre1.or(pre2).test(x)) {
				result.add(x);
			}
		}
		return result;
	}
	
	//取反negate
	public static List<Integer> filterEvenNeg(List<Integer> list,Predicate<Integer> pre){
		List<Integer> result = new ArrayList<>();
		for(Integer x:list) {
			if(pre.negate().test(x)) {
				result.add(x);
			}
		}
		return result;
	}
}

     (6)其它接口介绍

      JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在java.util.function包中被提供。

函数式接口

参数类型

返回类型

用途

BiFunction<T,U,R>

T,U

R

对类型为T,U参数应用操作,返回R类型的结果。

包含方法为Rapply(Tt,Uu);

UnaryOperator<T>

(Function子接口)

T

T

对类型为T的对象进行一元运算,并返回T类型的结果。

包含方法为Tapply(Tt);

BinaryOperator<T>

(BiFunction子接口)

T,T

T

对类型为T的对象进行二元运算,并返回T类型的结果。

包含方法为Tapply(Tt1,Tt2);

BiConsumer<T,U>

T,U

void

对类型为T,U参数应用操作。

包含方法为void accept(Tt,Uu)

ToIntFunction<T>

ToLongFunction<T>

ToDoubleFunction<T>

T

int

long

double

分别计算int、long、double、值的函数

IntFunction<R>

LongFunction<R>

DoubleFunction<R>

int

long

double

R

参数分别为int、long、double类型的函数

三、Stream API

1.概述

       在jdk1.8中,提供了一个Stream类型,可以对数据进行过滤。

       好处:比不断的自定义循环,要简单很多。

       代码示例

package com.xj.Test;

import java.util.ArrayList;

class Test {
	public static void main(String[] args) {
		ArrayList<String> names = new ArrayList<>();
		names.add("张飞");
		names.add("周瑜");
		names.add("赵云");
		names.add("鬼谷子");
		names.add("上官婉儿");
		names.add("东皇太一");
		names.add("百里守约");
		names.add("百里玄策");
		
		test0(names);
		test1(names);
		
	}
	//不使用stream获取集合中,性百里四个字名字,获取集合之后,还要打印集合的内容
	public static void test0(ArrayList<String> names) {
		ArrayList<String> result = new ArrayList<>();
		for(String name:names) {
			if(name.startsWith("百里") && name.length()==4) {
				result.add(name);
			}
		}
		for(String name:result) {
			System.out.println(name);
		}
	}
	
	//使用stream获取集合中,性百里四个字名字
	private static void test1(ArrayList<String> names) {
		names.stream().filter(x->x.startsWith("百里")).filter(x->x.length()==4).forEach(System.out::println);
	}
	
	
}

2.Stream类型数据的获取

      Collection的获取:调用stream()方法即可,返回Stream类型的对象。

      Map的获取:不能直接获取Stream类型。

     1、keySet().stream()

     2、values().stream()

     3、entrySet().stream()

     数组的获取:Stream中的of方法,Stream.of(数组)

     代码示例

package com.xj.Test;

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

class Test {
	public static void main(String[] args) {
		//Collectionn直接调用stream()
		Collection col = new ArrayList();
		Stream s1 = col.stream();
		
		List list = new ArrayList();
		Stream s2 = list.stream();
		
		Set set = new HashSet();
		Stream s3 = set.stream();
		
		Map map = new HashMap();
		Stream s4 = map.keySet().stream();
		Stream s5 = map.values().stream();
		Stream s6 = map.entrySet().stream();
		
		String[] strs = {"abc","sa","sdsf","sdfsd"};
		Stream<String> s7 = Stream.of(strs);
		s7.filter(x->x.length()==3).forEach(System.out::println);
		
	
	}
}

3.Stream中的常用方法

       Stream接口中的常用方法,用于对流中的数据,进行过滤、筛选或者操作。

       分类:

       1、终结方法:调用完成之后,返回值不再是Stream类型本身,无法继续调用Stream中的方法。

       例如:forEach、count

       2、延迟方法:调用完成之后,返回值还是Stream类型,可以继续调用Stream中的各种方法。

      例如:除了终结方法,全都是延迟方法

Stream<T>

filter(Predicate<? super T> predicate) 

返回由与此给定谓词匹配的此流的元素组成的流。

Stream<T>

limit(long maxSize) 

返回由此流的元素组成的流,截短长度不能超过 maxSize 。

Stream<T>

skip(long n) 

在丢弃流的第一个 n元素后,返回由该流的 n元素组成的流。

<R> Stream<R>

map(Function<? super T,? extends R> mapper) 

返回由给定函数应用于此流的元素的结果组成的流。

void

forEach(Consumer<? super T> action) 

对此流的每个元素执行操作。

long

count() 

返回此流中的元素数。

     代码示例

package com.xj.Test;

import java.util.ArrayList;

class Test {
	public static void main(String[] args) {
		ArrayList<String> names = new ArrayList<>();
		names.add("张飞");
		names.add("周瑜");
		names.add("赵云");
		names.add("鬼谷子");
		names.add("上官婉儿");
		names.add("东皇太一");
		names.add("百里守约");
		names.add("百里玄策");
		names.add("李白");
		
		//名字长度小于3
		//names.stream().filter(x->x.length()<3).forEach(System.out::println);
		
		//名字长度小于3的前三个
		//names.stream().filter(x->x.length()<3).limit(3).forEach(System.out::println);
	
		//跳过前三个
		//names.stream().skip(3).forEach(System.out::println);
		
		//统计有多少个
		//long l = names.stream().map(x->x.length()).count();
		//System.out.println(l);
		
		//返回每个名字的长度
		names.stream().map(x->x.length()).forEach(System.out::println);
	}
}

        练习

        有两个Arraylist集合,存储队伍中的多个成员姓名,使用Stream方式,对以下步骤进行操作:

        第一个队伍只要名字为3个字的成员姓名

        第一个队伍只要筛选之后的前三个人

        第二个队伍只要姓张的

        第二个队伍筛选之后不要前两个人

        将两个队伍合并成一个队伍

        合并之后的队伍中的所有人的Person(自定义类型)对象,存储到一个ArrayList集合中

        队伍1:宫本武藏、宋公明、苏有朋、石头人、时传祥、李耳、庄子、洪七公

        队伍2:帕瓦罗蒂、张三疯、赵薇薇、张自忠、孛儿只斤铁木真、张天爱、张翠花

package com.xj.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

class Test {
	public static void main(String[] args) {
		String str1 = "宫本武藏、宋公明、苏有朋、石头人、时传祥、李耳、庄子、洪七公";
		String str2 = "帕瓦罗蒂、张三疯、赵薇薇、张自忠、孛儿只斤铁木真、张天爱、张翠花";
		
		String[] ss1 = str1.split("、");
		String[] ss2 = str2.split("、");
		
		List<String> list1 = Arrays.asList(ss1);
		List<String> list2 = Arrays.asList(ss2);
		
		Stream<String> s1 = list1.stream().filter(x->x.length()==3).limit(3);
		Stream<String> s2 = list2.stream().filter(x->x.startsWith("张")).skip(2);
		
		Stream<String> ss = Stream.concat(s1, s2);
		
		List<Person> personList = new ArrayList<>();
		ss.forEach(x->{
			Person p = new Person(x);
			personList.add(p);
		});
		
		System.out.println(personList);
	}
}
class Person{
	
	private String name;
	
	
	public Person() {
		super();
	}

	public Person(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值