java8新特性笔记(一)

基本概念

函数式接口:接口只有一个抽象方法的接口,称之为函数式接口。
Lambda 表达式由 ->分隔为两部分,前面是方法的参数,后面的{}内是方法的代码。
lambda没有名称和文档,如果计算不是自解释的,或者超过几行,则不要将其放入lambda表达式中。


/**
 * Lambda 表示
 */
public class TestLamdba2 {
	@Test
		// 无参数,无返回值 形式
	void test1() {
		// 在jdk1.7之前,内部类使用外部变量,该变量必须是常量,1.8之后则没了.是一个常量
		int num = 1;
		Runnable runnable = new Runnable() {
			@Override
			public void run() {
				System.out.println("hello word" + num);
			}
		};
		System.out.println("------------------");
		Runnable runnable1 = () -> System.out.println("hello 无参数 无返回值");
		runnable1.run();

	}

	// 语法格式二: 有一个参数,无返回值
	@Test
	public void test2() {
		Consumer<String> consumer = System.out::println;
		consumer.accept("是顶级so");
	}

	// 语法格式三:剪头左侧如果只有一个参数,小括号可以不写
	@Test
	public void test3() {
		Consumer<String> consumer = x -> System.out.println(x);
		consumer.accept("是顶级so");
	}

	// 语法格式四:有多个参数,并且 lambda 体中有多条语句,必须有大括号
	@Test
	public void test4() {
		Comparator<Integer> comparable = (x, y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
		};

	}

	// 语法格式5:如果有多个参数,并且lambda 体有返回值,且只有一条语句
	@Test
	public void test5() {
		Comparator<Integer> comparable = (x, y) -> Integer.compare(x, y);
	}
	// 语法格式6:类型推断

}

内置函数式接口

更多看 java.util.function 包下的接口类

函数式接口函数描述符
Predicate(T) -> boolean
Consumer(T) -> void
Function< T, R >(T) -> R
Supplier( ) -> T
UnaryOperator(T) -> T
BinaryOperator(T, T) -> T
BiPredicate<L, R>(L, R) -> boolean
BiConsumer<T, U>(T, U) -> void
BiFunction<T, U, R>(T, U) -> R
/**
 * java8 内置的四大核心函数式接口。
 * Consumer<T> :消费性接口
 * void accept(T t)
 * Supplier<T> :供给型接口
 * T get();
 * Function() 函数型接口
 * R apply(T t)
 * predicate<T> 断言型接口
 * boolean test(T t)
 */
public class TestLambda4 {
	// 消费性接口
	public void happy(double money, Consumer<Double> consumer) {
		consumer.accept(money);
	}

	@Test
	public void test1() {
		happy(1000, (m) -> System.out.println("大保健啦啦啦"));
	}

	// 供给型接口
	// 需求:产生一些整数,并放入集合中
	public List<Integer> getNumList(int num, Supplier<Integer> supplier) {
		List<Integer> list = new ArrayList<>();
		for (int i = 0; i < num; i++) {
			Integer n = supplier.get();
			list.add(n);
		}
		return list;
	}

	// 测试供给型接口
	@Test
	public void test2() {
		List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
		for (Integer integer : numList) {
			System.out.println(integer);
		}
	}

	// 函数型接口
	// 需求:写个方法专门处理字符串
	public String strHandler(String s, Function<String, String> function) {
		return function.apply(s);
	}

	// 测试函数型接
	@Test
	public void test3() {
		String s = strHandler("/t/t/t 是尼克斯", (str) -> str.trim());
		System.out.println(s);
		// 其他字符串操作

	}

	// 断言型接口
	// 需求: 将满足条件的字符串,放入集合
	public List<String> filterStr(List<String> list, Predicate<String> pre) {
		List<String> stringList = new ArrayList<>();
		for (String s : stringList) {
			if (pre.test(s)) {
				stringList.add(s);
			}
		}
		return stringList;
	}

	// 测试断言型接口
	@Test
	public void test4() {
		List<String> list = Arrays.asList("hello", "fjc", "djfocfc");
		List<String> filterStr = filterStr(list, (s) -> s.length() > 3);
		for (String s : filterStr) {
			System.out.println(s);
		}
	}
}

lambda方法引用


/**
 *注意:还有构造器方法引用。
 * 方法引用:若lambda体中有方法已经实现了,我们可以使用“方法引用”
 * 主要有三种语法格式:、
 *  1:对象::实例方法名
 *  2: 类:: 静态方法
 *  3, 类::实例方法
*
* */
public class TestLambd5 {
	@Test
	public void test1(){
		Consumer<String> consumer = System.out::println;
//	等价于 PrintStream ps = System.out ; Consumer<String> consumer = ps::println
	}
	@Test
	public void test2(){
		Employee employee = new Employee();
		Supplier<String> sup=()->employee.getName();
		String s = sup.get();
		System.out.println(s);

		// 可以改写为
		Supplier<Integer> sup2 = employee::getAge;
	}
	// 类::静态方法
	@Test
	public void test3(){
		Comparator<Integer> comparator = (x,y)->Integer.compare(x,y);
		Comparator<Integer> comparator1 = Integer::compare;
	}
	// 类::实例方法名
	@Test
	public void test4(){
		BiPredicate<String,String> bip = (x,y)->x.equals(y);
		BiPredicate<String,String> bip2 = String::equals;

	}
	// lambda 构造器引用
	// 注意:函数式接口的参数列表要和接口抽象方法的参数列表保持一致
	// 调用的是无参构造器
	@Test
	public void test5(){
		Supplier<Employee> sup = ()->new Employee();
		// 构造器引用
		Supplier<Employee> supplier = Employee::new;
		Employee employee = supplier.get();
		System.out.println(employee);
	}

}

流操作

集合是存储数据的,Stream是操作数据的,在俩个端中间进行一系列操作,不会改变,原来的数据源。

StreamAPI 针对常见的集合数据处理,是对容器类的增强,将多个集合数据的多个操作以流水线的方式组合一起。

针对接口而非具体类型进行编程,可以降低程序的耦合性,提高灵活性,提高复用性。接口常被用于传递代码

(通过接口传递行为代码,就要传递一个实现了该接口的实例对象,最简洁是使用匿名类)

匿名类和表达式的区别

lambda表达式与匿名类很像,主要就是简化了语法,那它不是语法糖。java会为每个匿名类生成一个类,但lambda表达式不会,lambda表达式通常比较短,为每个表达式生成一个类会生成大量的类,性能会受到影响。

 public File[] listFiles(FilenameFilter filter) {
        String ss[] = list();
        if (ss == null) return null;
        ArrayList<File> files = new ArrayList<>();
        for (String s : ss)
            if ((filter == null) || filter.accept(this, s))
                files.add(new File(s, this));
        return files.toArray(new File[files.size()]);
    }
// 进行对比,去理解接口传递代码
File f = new File(".");
File[] files = f.listFiles(new FilenameFilter(){
    @Override
    public boolean accept(File dir,String name){
        if(name.endsWoth(".txt")){
            return true;
        }
        return false;
    }
})

使用

/**
* 使用三个步走
 * 1,创建stream
 * 2,中间操作
 * 3,终止操作
*
* */
public class TestStreamAPI1 {
	@Test
	public void test1(){
		// 1.从Collection集合中提供的Stream()
		List<String> list = new ArrayList<>();
		Stream<String> stream = list.stream();
		// 2,通过Arrays 中静态方法Stream()获取数组
		Employee[] employees = new Employee[10];
		Stream<Employee> stream1 = Arrays.stream(employees);

		// 3.通过Stream类的静态方法of()
		Stream<String> stream2 = Stream.of("aa", "vv", "cc");
		// 4,创建无限流
		// 迭代
		Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
		iterate.limit(10)
				.forEach(System.out::println);

		// 生成
	}

}

中间步骤

filter

该方法接受Predicate ,T->boolean,用于集合进行筛选,返回满足条件的元素。
例子:

// 筛选满足,以字母“J”开头的元素
		sourceList.stream()
				.filter(s-> s.startsWith("J"))
				.map(String :: toUpperCase)
				.forEach(System.out :: println);

只展示做什么,而不展示怎么做 这是Stream的一个优点

        long count = asList.stream()
                .filter(s -> s.length() > 3)
                .count();
        List<String> lengthUp4List = asList.stream()
                .filter(s -> s.length() > 4)
                .collect(Collectors.toList());
distinct

去重。filter和map都是无状态的,distinct不同,它是有状态的,
例子

		List<Integer> integerList = Arrays.asList(1, 2, 4, 5, 6, 6, 4, 2);
		integerList.stream()
				.filter(i-> (i%2==0))
				.distinct()
				.forEach(System.out::println);
skip/limit

skip跳过流中的n个元素(若元素不足,则返回空流)limit处理skip之后的流,处理maxSize个,后序的不在处理,和流水线做工一样。

例子:将学生列表按照分数排序,返回第三名到第五名

// 注意skip和limit的用法区别,以及如何配合使用
		List<Student> list = students.stream().
				sorted(Comparator.comparing(Student::getScore).reversed())
				.skip(2)
				.linit(3)
				.collect(Cokkectors.toList());

注意:skip和limit 只处理部分元素,就进入下一个流程,提前结束的操作称之为短路操作。

map

还有几个变形,方便后序进行求和等等处理
在这里插入图片描述

List<String> sourceList = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift");

		// 接受一个函数,这个函数会应用到每个元素上,并将其映射为一个新元素。
		// 返回是个流
		sourceList.stream()
				.map(String::length)
				.forEach(System.out::print);
		// 输出 4,10,6,3
flatMap

概述:flatMap用于将多个流合并成一个流,俗称流的扁平化。

注意点:Arrays.Stream可以将一个数组转换为一个流

例子

	// 目标返回 hello,word,老马,编程
		List<String> lines = Arrays.asList("hello word","老马 编程");

第一次尝试

// 下面返回是
		/* Stream<String[]> 数组,并不是想要的 Stream<String>
		 * [Ljava.lang.String;@60438a68
			[Ljava.lang.String;@140e5a13
		 * */
		lines.stream()
				.map(s->s.split(" "))
				.forEach(System.out::println);

第二次

	/*
		返回的是:各个流,需要把这些流连接为一个流,使用flatMap
		* java.util.stream.ReferencePipeline$Head@192d3247
			java.util.stream.ReferencePipeline$Head@3ecd23d9
		* */
		lines.stream()
				.map(s->s.split(" "))
				.map(Arrays::stream)
				.forEach(System.out::println);

在这里插入图片描述
idea还会提示,牛逼
最终

		lines.stream()
				.map(s->s.split(" "))
				.flatMap(Arrays::stream)
				.forEach(System.out::println);
	// 或者
			List<String> words = lines.stream()
				.flatMap(line->Arrays.stream(line.split("\\s+")))
				.collect(Collectors.toList());

还有几个变形
在这里插入图片描述


/**
 * 流的中间操作
 */
public class TestStreamAPI2 {
	/*
	 * 中间操作:
	 * 筛选与切片
	 * filter-接受Lambda ,从流中排除某些元素
	 * limit-截断流,使其元素不超过给定元素
	 * skip-跳过元素,返回一个丢掉前n个元素的不足n个
	 * distinct-筛选
	 *
	 * */
	List<Employee> employees = Arrays.asList(
			new Employee("张三1", 12, 2222),
			new Employee("张三2", 12, 2222),
			new Employee("张三3", 40, 2222),
			new Employee("张三4", 12, 22222),
			new Employee("张三5", 12, 2222)
	);

	@Test
	public void test1() {
		Stream<Employee> stream = employees.stream()
				//中间操作
				.filter((e) -> e.getAge() > 32);
		// 终止操作
		stream.forEach(System.out::println);
	}

	@Test
	public void test2() {
		employees.stream()
				.filter((e) -> {
					System.out.println("短路"); // 只迭代两次。要2个,就迭代俩次
					return e.getSalary() > 200;

				}).limit(2)
		.forEach(System.out::println);

	}
	@Test
	public void test4(){
		employees.stream()
				.filter((e)->e.getSalary()>2)
				.skip(2) // 跳过2个结果
				.forEach(System.out::println);

	}
	// 映射操作
	@Test
	public void test5(){
		List<String> list = Arrays.asList("aaa","bb","cc","dddd");
		list.stream()
				.map((str)->str.toUpperCase())
				.forEach(System.out::println);

		System.out.println("------------");
		employees.stream()
				.map(Employee::getName)
				.forEach(System.out::println);
		System.out.println("------------");
		// todo 注意体会
		Stream<Stream<Character>> streamStream = list.stream().map(TestStreamAPI2::filterCharacter);
		streamStream.forEach((sm)->{
			sm.forEach(System.out::println);
		});
		System.out.println("------------");

	}
	public static Stream<Character> filterCharacter(String str){
		List<Character> list = new ArrayList<>();
		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}
		return list.stream();
	}
}

终端操作

中间操作不触发实际的执行,返回值是stream。而终端操作触发执行,返回一个具体的值。

Match

接受一个谓词 predicate 返回一个boolean 值。用于判定流中的元素是否满足一定的条件。
allMatch(都满足返回true)、anyMatch(任意一个满足),noneMatch(都不满足)
注意:如果流为空,那么这几个函数的返回值都是true
在这里插入图片描述

例子

		List<String> sourceList = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift");
		boolean allMatch = sourceList.stream()
				.allMatch(s -> s.equals("Java"));
		System.out.println(allMatch);
find

包括 findFirst(取第一个),findAny(取满足条件任意一个)
例子:

List<String> sourceList = Arrays.asList("Java", "JavaScript", "python", "PHP", "C#", "Golang", "Swift");
		//满足长度小于4,元素有 "PHP", "C#"
		sourceList.stream()
				.filter(s -> s.length()<4)
				.findFirst()
				.ifPresent(System.out::println);


		sourceList.stream()
				.filter(s -> s.length()<4)
				.findAny()
				.ifPresent(System.out::println);
reduce

reduce----折叠。是max,min,count 的更加通用的函数,将流中的元素归约为一个值。
三个入参的,比前俩个更加灵活以及强大
有三个重载方法
在这里插入图片描述
例子:

	List<Integer> integerList = Arrays.asList(1, 2, 4, 5, 6, 6, 4, 2);
		// 一个入参的
		integerList.stream()
				.reduce(Integer::max)
				.ifPresent(System.out::println);
		integerList.stream()
				.reduce(Integer::min)
				.ifPresent(System.out::println);
		// 二个个入参的
		Integer sum = integerList.stream()
				.filter(i -> (i % 2 == 0))
				.reduce(0, Integer::sum);
		System.out.println(sum);
		// 三个入参的
		// 前两个灵活性不足,元素是什么类型的,输出也是什么类型的。比如:元素是int,累加之后int放不下,需要Long类型。下面这个就可以。
		// 当然不局限这个
		String string = integerList.stream()
				.reduce(0L, Long::sum, (a, b) -> 0L)
				.toString();
		System.out.println(string);

max,min,count,foreach
toArray

toArray 将流转换为数组

Object[] toArray();
<A> A[] toArrya(IntFunction<A []> generator)

例子 获取90分以上的学生数组

Student[] above90Arr = students.stream().filter(t->t.getScore()> 90 ).toArray(Student[] :: new);
// 这里时lamdba 表达式 的构造器引用(还有方法引用)
collect

collect方法用于收集流中的元素,并放到不同类型的结果中,比如List、Set或者Map
例子

List<String> filterList = list.stream()
        .filter(s -> s.startsWith("J"))
        .collect(Collectors.toList());

Stream toMap

list集合toMap 的时候,若是出现key冲突,并且你没有显示指定合并规则,讲抛出异常
在这里插入图片描述

        
// 发生重复key,不处理(或者说保留之前的)
       allLegalAccountName.stream().collect(Collectors.toMap(LegalAccountRefEntity::getLegalUnitId,LegalAccountRefEntity::getGroupAccountName,(k1,k2)->k1));

函数式数据处理思维

流定义了很多数据处理的基本函数,对于一个具体的数据处理问题,解决的主要思路就是组合利用这些基本函数,以声明式的方式简洁的实现期望的功能,这种思路就是函数式数据处理思维,想比直接利用容器类API命令思维,。

Stream API也与各种基于Unix 系统的管道命令类似。 Unix有很多命令,大部分命令只是专注于完成一件事情,但是可以通过管道的方式将多个命令链接起来,完成一些复杂的功能。

例子-分析访问nginx 日志,统计出访问次数最多的20个ip地址,及其访问次数

cat nginx_asscess.log | awk '{print $1 }'| sort | uniq -c | sort -rnk l | head -n 20

理解Collect

例子
List<Student> above90List() = student.stream().filter(t->t.getSorce()>90).collect(Collectors.toList())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值