Java教程

java-day-27

本文主要是介绍java-day-27,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

2021.11.2

 Lambda

 概述

Lambda表达式是一种没有名字的函数,也可称为闭包,是Java 8 发布的最重要新特性。

本质上是一段匿名内部类,也可以是一段可以传递的代码。

还有叫箭头函数的...

 为什么使用Lambda表达式

Lambda表达式就是一个匿名内部类的简写方式

使程序更加简洁清晰,编程效率也得到了提高

package study;

public class Part01_Lambda {
	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4 };
		// 常规遍历
		// for (int j : arr) {
		// System.out.println(i);
		// }
		// 1 实现类
		// forEach(arr ,new A());
		// 2 匿名内部类
		forEach(arr, new Array() {
			@Override
			public void m1(int i) {
				System.out.println(i + "-====-");
			}
		});
		// 3 lambda表达式
		forEach(arr, (i) -> System.out.println(i +1+ "++++++++++"));
	}

	// 封装的功能,完成遍历操作,但是需要传递数组,和要做的事
	// 该方法只是帮我们遍历而已
	public static void forEach(int[] arr, Array array) {
		for (int i : arr) {
			array.m1(i);
		}
	}
}

// 封装要做的事
interface Array {
	void m1(int i);
}

class A implements Array {

	@Override
	public void m1(int i) {
		System.out.println(i + "---");
	}

}

 

规则:

可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。

可选的大括号:如果主体包含了一个语句,就不需要使用大括号。

如果不写{}  return 不能写  分号不能写

可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值

如果只有一条语句,并且是返回值语句,就可以不写return 不写 {}  

如果写上{}  就必须写return 和 ;

如果有 多条语句,必须写{}  return 和 ;  也必须写

例子: 

package study;

import java.util.ArrayList;
import java.util.List;

public class Part02_Lambda_02 {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		// 常规写法
		// for (Integer integer : list) {
		// System.err.println(integer);
		// }

		// 匿名内部类写法
		// list.forEach(new Consumer<Integer>() {
		// @Override
		// public void accept(Integer t) {
		// System.out.println(t);
		// }
		// });

		// lambda写法
		list.forEach(x -> System.out.println(x));
	}
}
package study;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Part03_Lambda_03 {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(11);
		list.add(2);
		list.add(3);
		// Collections.sort(list, new Comparator<Integer>() {
		// @Override
		// public int compare(Integer o1, Integer o2) {
		// return o2-o1;
		// }
		// });

		Collections.sort(list, (x, y) -> y - x);

		System.out.println(list);
	}
}
class B {
	@Override
	public boolean equals(Object obj) {
		return false;
	}
}

函数式接口

介绍

英文称为Functional Interface

其本质是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

核心目标是为了给Lambda表达式的使用提供更好的支持,进一步达到函数式编程的目标,可通过运用函数式编程极大地提高编程效率。

其可以被隐式转换为 lambda 表达式。

 特点

函数式接口是仅制定一个抽象方法的接口

可以包含一个或多个静态或默认方法

专用注解即@FunctionalInterface 检查它是否是一个函数式接口,也可不添加该注解

如果有两个或以上 抽象方法,就不能当成函数式接口去使用,也不能添加@FunctionalInterface这个注解

如果只有一个抽象方法,那么@FunctionalInterface注解 加不加 都可以当做函数式接口去使用

无参构造与有参构造: 

package study;

import java.util.function.Function;
import java.util.function.Supplier;

public class Part04_Constryctarcakk {
	public static void main(String[] args) {
		// 无参构造
		Supplier<Object> objSi = Object::new;
		System.out.println(objSi.get());

		// 有参构造
		Function<String, Integer> function = Integer::new;
		System.out.println(function.apply("123"));
		// new Integer("123");
	}
}
无参情况
public class FunInterface_01 {
	// 自定义静态方法,接收接口对象
	public static void call(MyFunctionInter func) {
		// 调用接口内的成员方法
		func.printMessage();
	}

	public static void main(String[] args) {
		// 第一种调用 : 直接调用自定义call方法,传入函数
		FunInterface_01.call(() -> {
			System.out.println("HelloWorld!!!");
		});

		// 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
		MyFunctionInter inter = () -> {
			System.out.println("HelloWorld2!!!!");
		};
		// 调用这个实现的方法
		inter.printMessage();
	}
}
// 函数式接口
@FunctionalInterface
interface MyFunctionInter {
	void printMessage();
}
有参情况
public class FunInterface_02 {
	// 自定义静态方法,接收接口对象
	public static void call(MyFunctionInter_02 func, String message) {
		// 调用接口内的成员方法
		func.printMessage(message);
	}

	public static void main(String[] args) {
		// 调用需要传递的数据
		String message = "有参函数式接口调用!!!";

		// 第一种调用 : 直接调用自定义call方法,传入函数,并传入数据
		FunInterface_02.call((str) -> {
			System.out.println(str);
		}, message);

		// 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
		MyFunctionInter_02 inter = (str) -> {
			System.out.println(str);
		};
		// 调用这个实现的方法
		inter.printMessage(message);
	}
}

// 函数式接口
@FunctionalInterface
interface MyFunctionInter_02 {
	void printMessage(String message);
}

Supplier<T>接口    代表结果供应商,所以有返回值,可以获取数据

有一个get方法,用于获取数据

package study;

import java.util.function.Supplier;

/**
 * Supplier 代表供应商,有返回值,可以获取数据使用
 * 
 * 提供一个get方法
 * @author 落华见樱
 *
 */
public class Part07_Functions_02 {
	public static void main(String[] args) {
		String string = "张三";
		String result = getResult(()->"我叫"+string);
		System.out.println(result);
	}
	
	public static String getResult (Supplier<String> supplier){
		return supplier.get();
	}
}

Consumer<T>接口    消费者接口所以不需要返回值

有一个accept(T)方法,用于执行消费操作,可以对给定的参数T 做任意操作

package study;

import java.util.function.Consumer;

/**
 * Consumer 代表了消费者,提供了accept方法 有参数 但是无返回值
 * @author 落华见樱
 *
 */
public class Part06_Functions_01 {
	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4 };
		// 常规遍历
		// for (int j : arr) {
		// System.out.println(i);
		// }

		// 3 lambda表达式
		forEach(arr, (i) -> System.out.println(i + "++++++++++"));
	}

	// 封装的功能,完成遍历操作,但是需要传递数组,和要做的事
	// 该方法只是帮我们遍历而已
	public static void forEach(int[] arr, Consumer<Integer> c) {
		for (int i : arr) {
			c.accept(i);
		}
	}
}

Function<T,R>接口  表示接收一个参数并产生结果的函数

顾名思义,是函数操作的

有一个R apply(T)方法,Function中没有具体的操作,具体的操作需要我们去为它指定,因此apply具体返回的结果取决于传入的lambda表达式

package study;

import java.util.function.Function;

/**
 * Function : 有参有返回值,提供了 apply方法
 * @author 落华见樱
 *
 */
public class Part08_Functions_03 {
	public static Integer m1(String string ,Function<String, Integer> fun){
		return fun.apply(string);
	}
	
	public static void main(String[] args) {
		String string = "123";
		int result = m1(string,s->Integer.parseInt(s)*10);
		System.out.println(result);
	}
}

Predicate<T>接口   断言接口

就是做一些判断,返回值为boolean

有一个boolean test(T)方法,用于校验传入数据是否符合判断条件,返回boolean类型

public class _06_JdkOwn_04 {
	// 自定义方法,并且 Predicate 接收String字符串类型
	public static void call(Predicate<String> predicate, String isOKMessage) {
		boolean isOK = predicate.test(isOKMessage);
		System.out.println("isOK吗:" + isOK);
	}

	public static void main(String[] args) {
		// 传入的参数
		String input = "ok";
		call((String message) -> {
			// 不区分大小写比较,是ok就返回true,否则返回false
			if (message.equalsIgnoreCase("ok")) {
				return true;
			}
			return false;
		}, input);
	}
}

 方法引用和构造器调用

package study;

import java.util.function.Supplier;

/**
 *  对象引用::成员方法名
 * 
 * 要求 : 需要根据调用方法的入参和出参去选择对应的函数式接口才行
 * @author 落华见樱
 *
 */
public class Part09_FunCall_01 {
	public static void main(String[] args) {
		Integer i1 = new Integer(123);
		// 常规lambda写法
		Supplier<String> su = () -> i1.toString();
		System.out.println(su.get());

		// 方法引用写法
		su = i1::toString;
		System.out.println(su.get());
	}
}

 

package study;

import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * 类名::静态
 * @author 落华见樱
 *
 */
public class Part10_FunCall_02 {
	public static void main(String[] args) {

		Function<String, Integer> fun = Integer::parseInt;
		System.out.println(fun.apply("123"));

		fun = new Function<String, Integer>() {
			@Override
			public Integer apply(String t) {
				// TODO Auto-generated method stub
				return null;
			}
		};

		fun = x -> Integer.parseInt(x);
		fun = Integer::parseInt;

		// 前两个是入参,第三个是返回值
		BiFunction<Integer, Integer, Integer> bif = Integer::max;
		System.out.println(bif.apply(123, 323));
		test((B123 x) -> System.out.println(x));
	}

	public static void test(Aasa a) {

	}
}

interface Aasa {
	public void m1(B123 b);
}

class B123 {

}
package study;

import java.util.function.BiPredicate;

/**
 * 类名::成员方法名
 * @author 落华见樱
 *
 */
public class Part11_FunCall_03 {
	public static void main(String[] args) {
		BiPredicate<String, String> bp = String::equals;
		System.out.println(bp.test("abc", "abc"));
	}
}
package study;

import java.util.function.Function;

public class Part05_ArrayCall {
	public static void main(String[] args) {
		Function<Integer, Integer[]> function = Integer[]::new;
		Integer[] arr = function.apply(10);
		
		for (Integer integer : arr) {
			System.out.println(integer);
		}
	}
}

Stream API

 概念说明

数据渠道、管道,用于操作数据源(集合、数组等)所生成的元素序列。

集合讲的是数据,流讲的是计算

即一组用来处理数组,集合的API。

 特点

Stream 不是数据结构,没有内部存储,自己不会存储元素。

Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

不支持索引访问。

延迟计算

支持并行

很容易生成数据或集合

支持过滤,查找,转换,汇总,聚合等操作。

​​​​​​​ 应用场景

流式计算处理,需要延迟计算、更方便的并行计算

更灵活、简洁的集合处理方式场景

 代码实现

 运行机制说明

Stream分为源source,中间操作,终止操作。

流的源可以是一个数组,集合,生成器方法,I/O通道等等。

一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。

中间操作也称为转换算子-transformation

Stream只有遇到终止操作,它的数据源会开始执行遍历操作。

终止操作也称为动作算子-action

因为动作算子的返回值不再是 stream,所以这个计算就终止了

只有碰到动作算子的时候,才会真正的计算

package study;

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

/**
 * 生成流
 * @author 落华见樱
 *
 */
public class Part12_Stream {
	public static void main(String[] args) {
		// 1 数组转换为流
		String[] strings = { "q", "w", "e", "r" };
		Stream<String> stream1 = Stream.of(strings);

		// 2 通过集合
		// Arrays.asList : 把数组转换为集合
		List<String> list = Arrays.asList(strings);
		stream1 = list.stream();
		
		// 3 通过Stream的generate创建
		// 但是是一个无限流(无限大),所以经常结合limit一起使用,来限制最大个数
		// generate参数是一个 Supplier ,而 Supplier中有一个get方法用于获取数据
		// 而 get方法的返回值,会作为数据保存到这个流中,下面程序也就意味中该流中的数据都是1
		Stream<Integer> stream2 = Stream.generate(()->1);
		// limit 是中间操作,设置流的最大个数
		// forEach 遍历,是终止操作
		stream2.limit(5).forEach(x->System.out.println(x) );
		
		// 4 通过String.iterate
		// 同上,是无限流
		// 参数1 是起始值, 参数二 是function, 有参有返回值
		// x+2 等于步长为二  for(int i =1 ; true ; i+=2)
		Stream<Integer> stream3 = Stream.iterate(1, x->x+2);
		stream3.limit(10).forEach(x->System.out.println(x));
		
		// 5 已有类的API
		String string = "abc";
		IntStream chars = string.chars();
		chars.forEach(x->System.out.println(x));
	}
}
这篇关于java-day-27的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!