记录Java1.8新特性

Lambda表达式

* Lambda表达式是一种没有名字的函数 , 也可以称之为闭包 , 是Java8的新特性
 * 
 * 本质是一个匿名内部类 , 又叫做箭头函数
 * 
 * 使用它就是为了方便简洁  匿名内部类与箭头函数是一个东西 ,所以两种写法所表示的含义是相同的
 * 
 * 闭包是能够读取其他函数内部变量的函数
 * 
 * 允许把方法作为一个参数传递 , 使用Lambda表达式 , 可以使代码变得更加简洁紧凑
 * 
 * -> : 箭头操作符
 * 
 * 语法结构 : 
 * 		无参无返回值 : Runnable r1 = -> {System.out.println("Hello World");};
 * 		
 * 		可选类型声明 : 不需要声明数据类型 , 编译器可以识别参数值 
 * 		可选的参数()括号 : 一个参数不需要定义括号 , 但是多个参数必须定义括号
 * 		可选的大括号 : 如果主体内只有一个语句 , 就可以不加大括号 
 * 		可选的返回值关键字 : 如果主体内只有一个语句 ,且是返回语句 , return就可以不写
 * 										如果有多条语句 , 大括号和return就都得写

用法 与 对比(1.8之前可以怎么写,之后可以怎么写)

public class Lambda_01_01 {
	public static void main(String[] args) {
		// 创建数组
		String[] arr = {"one","two","three","four"};
		// 转化为集合
		List<String> list = Arrays.asList(arr);
		// 遍历
		for (String string : list) {
			System.out.println(string);
		}
		System.out.println("<------------------------------------------->");
		
		// 1.8新写法
		// 返回一个参数 , 不需要声明类型  , 只有一个语句 
		// 一个参数的时候 , 可以不加() 一条语句的时候 , 可以不加{}和;
		// 本质是回调函数
		list.forEach(x -> System.out.println(x));
		System.out.println("<------------------------------------------->");
		// 或者
		list.forEach(y -> {
			System.out.println(y);
		});
	}
}

用新写法进行排序

public class Lambda_02 {
	public static void main(String[] args) {
		// 创建数组
		Integer[] arr = {2,6,8,1,3,9,5};
		// 转换为集合
		List<Integer> list = Arrays.asList(arr);
		// 降序 这是非箭头函数写法 , 覆写Comparator的compare方法
		list.sort(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o2-o1;
			}
		});
		System.out.println(list);
		
		// 1.8新写法
		// 升序  在函数里调用函数 
		list.sort((o1 , o2) -> Integer.compare(o1, o2) );
		// 下面这种写法就是与上面的写法作用是一样的
		list.sort((o1 , o2) -> o1-o2 ); // (o1 , o2) 是参数 , o1-o2是返回值
		System.out.println(list);
	}
}

Functional interface 函数式接口

 * Functional interface
 * 函数式接口 : 本质就是一个只有一个抽象方法 , 但是可以有多个非抽象方法的接口
 * 这个接口的目的就是为lambda表达式的使用提供更好的支持 , 进一步达到函数式编程的目标 , 提高开发效率
 * 
 * 特点 : 函数式接口是仅指定一个抽象方法的接口
 * 			可以保护多个静态方法和默认方法
 * 			专用注解 : @FuntionalInterface  , 检查是否是一个函数式接口 , 也可以不写该注解
 * 			如果有两个及以上的抽象方法 , 就不能当做函数式接口去使用 , 同时也不能添加 @FuntionalInterface 注解
 * 
 * 回调函数 : 就是方法需要传入一个参数 (参数时方法)  , 并且在该方法中对这个传入的方法进行调用

无参时

public class Functional_02_01 {
	public static void main(String[] args) {
		// 实现类的方法
		Test test = new Test();
		call(test);
		
		// 匿名内部类的方法
		call(new MyFunctionInter() {
			
			@Override
			public void printMessage() {
				System.out.println("匿名内部类的实现方法");
			}
		});
		
		// 1.8新写法 Lambda写法
		call(() -> System.out.println("Lambda表达式的实现方法"));
		
		// 创建函数对象的实现方法  无参的需要加()  
		MyFunctionInter Inter = () -> System.out.println("创建函数对象的实现方法");
		call(Inter);
	}
	// call方法可以调用MyFunctionInter的printMessage方法
	public static void call(MyFunctionInter func){
		func.printMessage();
	}
}

@FunctionalInterface
// 加上这个之后 , 会对下面的类进行检查 , 如果不是只有一个抽象方法 , 就会报错
interface MyFunctionInter{
	void printMessage();
}
class Test implements MyFunctionInter{

	@Override
	public void printMessage() {
		System.out.println("Test实现MyFunctionInter接口");
	}
	
}

有参时

/**
 * 有参数的情况
 *  这两个都是自定义的情况的简单语法 , 一般不这么用 , JDK有自带的四种函数式接口 
 *  当这四个都不能满足我们的需要的时候 , 才需要自定义
 * @杜智慧
 *
 * @Date 2021年2月2日
 */
public class Functional_02_02 {
	public static void main(String[] args) {
		String str = "有参数的函数式接口调用";
		// 匿名内部类的方法
		call(new MyFunctionInter2() {
			
			@Override
			public void printMessage(String str) {
				System.out.println(str);
			}
		}, str);
		
		// Lambda的方法  一个参数 可以不加括号
		call(x->System.out.println(x), str);
		
		// 创建函数对象
		MyFunctionInter2 inter2 = x->System.out.println(x);
		call(inter2, str);
	}
	
	// 与Functional_02_01里是一样的
	public static void call(MyFunctionInter2 func , String str){
		func.printMessage(str);
	}
}

@FunctionalInterface
interface MyFunctionInter2 {
	void printMessage(String str);
}

JDK自带的函数式接口

Supplier

 * Supplier<T> 接口 : 表示供应商 , 所以有返回值 , 可以获取数据  *  其内只有 get方法
public class Jdk_Own_02 {
	public static void main(String[] args) {
		/**
		 * Supplier
		 */
		String result = SupplierGetRusult(new Supplier<String>() {

			@Override
			public String get() {
				return "杜智慧_1";
			}
		});
		System.out.println(result);
		
		// Lambda 写法
		result = SupplierGetRusult(()-> "杜智慧_2");
		System.out.println(result);
		
		// 创建Supplier容器  这一步并不会创建对象
		Supplier<Jdk_Own_02> sup = Jdk_Own_02::new;
		Jdk_Own_02 jo1 = sup.get(); // 在这一步创建对象 
		Jdk_Own_02 jo2 = sup.get(); // 在这一步创建对象 
		// Functional_02.Jdk_Own_02@1218025c
		System.out.println(jo1);
		// Functional_02.Jdk_Own_02@816f27d
		System.out.println(jo2); // 每get一次 , 就获取一个对象
	}
	/**
	 * SupplierGetRusult
	 * @param function
	 * @return
	 */
	public static String SupplierGetRusult(Supplier<String> function){
		return function.get();
	}
	
	
}

Consumer

 * Consumer<T>接口 , 表示消费者接口 , 没有返回值
 * 
 * accept(T t) 用于执行消费操作
public class Jdk_Own_03 {
	public static void main(String[] args) {
		String message = "我是杜智慧";
		ConsumerGetRusult(x->System.out.println(x), message);
		// 匿名内部类的写法
		ConsumerGetRusult(new Consumer<String>() {

			@Override
			public void accept(String t) {
				System.out.println(t);
			}
		}, message);
		
	}
	/**
	 * ConsumerGetRusult
	 * @param function
	 * @param message
	 */
	public static void ConsumerGetRusult(Consumer<String> function , String message){
		function.accept(message);
	}
	
}

Function

 * Function<T , R> 接口 : 表示接收一个参数 , 并产生一个结果
public class Jdk_Own_04 {
	public static void main(String[] args) {
		// lambda写法
		int num = converTyoe(x->Integer.parseInt(x), "123");
		System.out.println(num);
		// 创建函数对象的实现方法  
		Function<String , Integer> x1 = x->Integer.parseInt(x);
		int num1 = x1.apply("123");
		System.out.println(num1);
	}
	// 字符串-->数字
	public static int converTyoe(Function<String , Integer> function , String str){
		int num = function.apply(str);
		return num;
	}
}

Predicate 断言接口

* Predicate<T> 接口 : 断言接口 , 就是做一些判断
 * boolean test(T) 用于做校验比较操作
public class Jdk_Own_05 {
	public static void main(String[] args) {
		String message = "ok";
		boolean result = call(x->x.equals("ok"), message);
		System.out.println(result); // true
	}
	// Predicate<String> predicate是一个接口  这就是回调函数 , 允许函数作为一个参数传入
	public static boolean call(Predicate<String> predicate , String message){
		return predicate.test(message);
	}
}

方法和构造器

对象的引用::实例方法

public class FunCall_03_01 {
	public static void main(String[] args) {
		Integer i1 = new Integer(12356);
		
		// 方法引用的写法  i1是一个对象名 , toString 是一个实例方法
		Supplier<String> str1 = i1::toString;
		System.out.println(str1); // FunCall_03.FunCall_03_01$$Lambda$1/791452441@1c20c684
		System.out.println(str1.get()); // 12356
		
		// Lambda写法
		Supplier<String> str2 = ()->i1.toString();
		System.out.println(str2); // FunCall_03.FunCall_03_01$$Lambda$2/531885035@548c4f57
		System.out.println(str2.get()); // 12356
	}
}

类名::静态方法名

public class FunCall_03_02 {
	public static void main(String[] args) {
		// 两个参数 , 一个返回值  常规Lambda写法
		BiFunction<Integer, Integer, Integer> bif = (x,y)->Integer.max(x, y);
		int apply = bif.apply(10, 11);
		System.out.println(apply);
		
		// 方法引用的写法
		BiFunction<Integer, Integer, Integer> bif1 = Integer::max;
		int apply1 = bif.apply(10, 11);
		System.out.println(apply1);
	}
}

类名::实例方法

public class FunCall_03_03 {
	public static void main(String[] args) {
		BiPredicate<String, String> predicate = (x , y)->x.equals(y);
		System.out.println(predicate.test("a", "b"));
		
		// 方法引用的写法  equals方法 类名是String
		BiPredicate<String, String> predicate1 = String::equals;
		System.out.println(predicate1.test("a", "a"));
	}
}

构造器调用

public class ConstructorCall_04 {
	public static void main(String[] args) {
		// 无参的构造器   ::new
		// 常规的lambda写法
		Supplier<Object> objsup = ()->new Object();
		System.out.println(objsup); // FunCall_03.FunCall_03_04$$Lambda$1/791452441@1fb3ebeb
		
		// 方法引用
		Supplier<Object> objsup1 = Object::new;
		System.out.println(objsup1); // FunCall_03.FunCall_03_04$$Lambda$2/303563356@816f27d
		
		// 有参构造器
		// 常规lambda写法
		Function<String, Integer> function  = (x)-> new Integer(x);
		System.out.println(function);
		
		// 方法引用的写法
		Function<String, Integer> function1  = Integer::new;
		System.out.println(function1);
	}
}

数组引用

public class ArrayCall_05 {
	public static void main(String[] args) {
		// lambda写法
		// 需求 定义一个Integer数组 长度为n
		// T代表入参 , R代表返回值 入参应该是数字(长度) , 返回值应该是一个数组
		Function<Integer, Integer[]> function = n->new Integer[n]; 
		Integer[] arr = function.apply(10);
		System.out.println(arr.length);
				
				
		// 数组引用写法
		Function<Integer, Integer[]> function1 = Integer[]::new;
		Integer[] arr1 = function1.apply(11);
		System.out.println(arr1.length);
	}
}

Stream API

 * Java8中有两大最为重要的改变第一个是Lambda 表达式 , 另外一个则是Stream API
 * Stream API把真正的函数式编程引入到了Java中 , 这是目前为止对Java类库最好的补充
 * Stream API可以极大的提升程序员的上产效率 ,让程序员写出高效率、干净、简洁的代码
 * 
 * 
 * 简单来讲 , 就是Stream API 提供了一种高效且易于使用的处理数据的方式
 * 
 * Stream 自己不会存储元素 , 不会改变源对象 , 相反 , 他会返回一个新的Stream
 * 且Stream操作是延迟执行的 , 就是说 , 他们会等到需要结果的时候才会执行 
 * 
 * 
 * 运行机制 : 分为 源(source) , 中间操作 , 终止操作三部分
 * 
 * 1 创建Stream
 * 2 中间操作 : 也叫做转换算子 ,  这个操作可以是一个操作链 , 在这个链式操作里  , 这个流一直保持着流的状态 
 * 3 终止操作 : 也叫做动作算子 , 这是真正执行运算的操作 , 且它的返回值也不再是一个流 , 计算到此终止

创建流的五种方式

public class StreamAPI_01 {
	public static void main(String[] args) {
		// 通过数组Stream.of
		String[] strings = {"a","b","c","d"};
		Stream<String> stream1 = Stream.of(strings);
		
		// 通过集合
		List<String> strings2 = Arrays.asList(strings);
		Stream<String> stream2 = strings2.stream();
		
		// 通过Stream.generate方法
		// 这是一个无限流 , 通过这种方式创建的流 , 最好使用limit进行最大数量限制
		// generate的参数时Supplier , 只有一个get方法 , 是无参有返回值的
		// get方法的返回值 , 作为整个集合中的数据 , 下面这个等于都赋值为1
		Stream<Integer> generate = Stream.generate(()->1);
		// 可以通过limit限制最多元素个数
		generate.limit(5).forEach(x->System.out.print(x + " "));   // 1 1 1 1 1 
		System.out.println();
		
		// 通过Stream.iterate方法来创建
		// 这也是一个无限流 , 也是使用limit进行最大数量限制
		// 第一个参数是起始值 , 第二个参数是UnaryOperator 继承了Function 所以有参有返回值
		Stream<Integer> iterate = Stream.iterate(1, x->x+2);
		iterate.limit(5).forEach(x->System.out.print(x + " ")); 
		System.out.println();
		
		// 已有类的Stream源生成API
		String string = "abc";
		IntStream chars = string.chars();
		chars.forEach(x->System.out.print(x + " ")); // 97 98 99 
	}
}

常用的转换算子

 * filter distinct map limit skip faltMap等
 * 
 * filter : 对元素进行过滤 , 不符合条件的就不要
 * 
 * distinct : 去掉重复
 * 
 * map : 可以理解为在遍历集合的过程中 , 对元素进行操作 , 比如进行判断  
 * 集合元素是否大于2  返回值为Boolean型 , 或者对集合元素进行更改 , 比如 , 每个元素自身加一
 * 与filter类似 , 但是filter不能对元素进行更改
 * 
 * limit : 取一个集合中的前几个数据 (也可以理解为设置最大条数)
 * 
 * skip : 跳过多少个元素
 * 
 * faltMap : 解决一个字符串数组 , 返回单一的字符串使用faltMap
 * 
 * 这些算子并不能真正的进行计算 , 只有终止算子(动作算子)会真正进行计算操作
public class StreamAPI_02 {
	public static void main(String[] args) {
		String[] arr = {"a","b","c","d"};
		List<String> strings = Arrays.asList(arr);
		Stream<String> stream = strings.stream();
		/**
		 * filter         返回值是false的就会放弃 , 即不符合条件的不要
		 */
		// collect是动作算子 , 把符合条件的转换为集合
		List<String> value = stream.filter(x -> x.equals("a")).collect(Collectors.toList());
		System.out.println(value);
		// 再次调用这句话会报错 stream has already been operated upon or closed 
		// 意思是说 流已经被操作或关闭
		// Stream使用之后必须重新生成新的Stream , 不能使用原来的
		// 链式调用是可以的  .filter(x -> x.equals("a")).filter(x -> x.equals("a")). 
		// 原因在于算子的返回值都是流 , 所以再操作流是可以的 , 但是就算是将这个操作拆分为两句话
		// 都是不可以的 , 因为那样的话 , 就再次调用的时候 . 就已经不是流了
		// List<String> value = stream.filter(x -> x.equals("a")).filter(x -> x.equals("a")).collect(Collectors.toList());
		//List<String> value1 = stream.filter(x -> x.equals("a")).collect(Collectors.toList());
		
		/**
		 * skip : 跳过n个元素
		 */
		stream  = strings.stream(); // 重新生成流  否则会报错
		value = stream.skip(1).collect(Collectors.toList()); // 跳过第一个
		System.out.println(value);
		/**
		 * map : 可以理解为是在遍历集合的过程中 , 对元素进行操作 
		 */
		stream  = strings.stream(); // 重新生成流  否则会报错
		List<Boolean> value1 = stream.map(x-> x.equals("a")).collect(Collectors.toList());
		System.out.println(value1);  // [true, false, false, false]
		// 更改集合元素 
		stream  = strings.stream(); // 重新生成流  否则会报错
		value = stream.map(x->x+"-->").collect(Collectors.toList());
		System.out.println(value); // [a-->, b-->, c-->, d-->]
		/**
		 * distinct : 去掉重复
		 */
		stream  = strings.stream(); // 重新生成流  否则会报错
		value = stream.distinct().collect(Collectors.toList());
		System.out.println(value);
		/**
		 * faltMap : 解决一个字符串数组 , 返回单一的字符串使用faltMap
		 */
		String[] arr1 = {"1,2,3" , "a,b,c"};
		strings = Arrays.asList(arr1);
		// 现在集合里 , 有两个数据 , 一个是1,2,3  另一个是a,b,c
		// 把数组中的每一个元素都拿出来 , 分别以逗号分隔 , 形成两个字符串数组
		stream  = strings.stream(); // 重新生成流  否则会报错 
		value = stream.map(x->x.split(",")).flatMap(array->Arrays.stream(array)).collect(Collectors.toList());
		System.out.println(value); // [1, 2, 3, a, b, c]
	}
}

常用的动作算子

 * 		forEach : 循环
 * 
 * 用于计算的 : min , max , count , average
 * 
 * 用于匹配的 : anyMatch , allMatch , noneMatch , findFirst , findAny
 * 
 * 汇聚 : reduce 
public class StreamAPI_03 {
	public static void main(String[] args) {
		String[] arr = {"a","b","c"}; 
		List<String> strings = Arrays.asList(arr);
		System.out.println(strings);  // [a, b, c]
		Stream<String> stream = strings.stream(); // 创建流
		
		// forEach   filter 对元素进行过滤
		stream.filter(x->x.equals(x)).forEach(x->System.out.println(x));
		
		// count
		stream = strings.stream(); // 重新生成流
		// 只有动作算子显示不出来它的优势  , 一般是跟转换算子一起使用才会显示出优势
		// 比如 , 统计有几个a
		long count = stream.filter(x->x.equals("a")).count();
		System.out.println(count); // 1
		
		// collect 收集器 把结果收集组织成集合
		stream = strings.stream();
		List<String> list = stream.map(x->x).collect(Collectors.toList());
		System.out.println(list); // [a, b, c]
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值