Java8基础知识

Java8 => 【函数式编程(functional programming)】
主要特性:

  • Lambda表达式(Lambda Expression)
  • 方法引用(Method Reference)
  • 流(Stream)

Lambda表达式

函数式接口是一种包含单一抽象方法(single abstract method)的接口。

  • Runnable接口的匿名内部类实现
public class RunnableDemo{
  public static void main(String[] args){
      new Thread(new Runnable() {
          @Override
          public void run(){
            System.out.println("inside runnable using an anonymous inner class");
          }
      }).start();
  }
}

方法引用

使用方法引用(Method Reference)来访问某个现有的方法,并将其作为lambda表达式进行处理。

Lambda表达式本质上是【将方法作为对象】进行处理,那么方法引用就是将现有方法作为Lambda表达式进行处理。

Eg: java.lang.Iterable接口的forEach方法传入Consumer作为参数。Consumer可以作为lambda表达式或方法引用来实现。

Stream.of(3, 1, 4, 1, 5, 9).forEach(x -> System.out.println(x));

Stream.of(1, 2, 3, 4, 5).forEach(System.out::println);

Consumer<Integer> printer = System.out::println;
Stream.of(1, 2, 3, 4, 5, 6, 7, 8).forEach(printer);

流依次产生一系列元素,但不会将他们存储在任何为止,也不会对原始源进行修改。

@Slf4j
public class Demo01 {
	public static void main(String[] args) {
		List<Double> myRandomSeed = Stream.generate(Math::random)
				.limit(10)
				.map(x -> Math.round(x * Math.pow(10, 2)) / Math.pow(10, 2))
				.collect(Collectors.toList());
		// [0.46, 0.24, 0.17, 0.18, 0.11, 0.31, 0.04, 0.51, 0.14, 0.18]
		System.out.println(myRandomSeed);
		/*
		* Stream接口定义的generate方法传入Supplier作为参数。Supplier是一个函数式接口
		* 其单一抽象方法get不传入任何参数且只生成一个结果。
		* Math累的random方法与get方法的签名相互兼容,因为random方法同样不传入任何参数,
		* 且产生一个0 - 1 之间,均匀分布的双精度伪随机数。
		* 方法引用 Math::random表示该方法是Supplier接口的实现。
		*
		* Stream.generate方法产生的是一个无限流(infinite stream)
		**/
	}
}

语法

方法引用包括以下三种形式,其中一种存在一定的误导性。

  • object::instanceMethod : 引用特定对象的实例方法, eg: System.out::println

  • Class:staticMethod: 引用静态方法,eg: Math::max

  • Class::instanceMethod: 调用特定类型的任意对象的实例方法,eg: String::length

最后一种形式我们说Java开发中一般类名只能调用Σ(っ °Д °;)静态方法。Lambda表达式和方法引用在任何情况下都不能脱离上下文存在。

// 相当于System.out::println
x -> System.out.println(x)
上下文提供了x的值,其被用作方法的参数
// 静态方法max与之类似相当于Math::max
(x,y) -> Math.max(x,y)

此时,上下文需要提供两个参数,Lambda表达式返回较大的参数。

x -> x.length()  ===> 相当于 String::length

当上下文提供x的值时,它将用作方法的目标而非参数。

从类引用(class reference)调用多参数实例方法

List<String> strings = Arrays.asList("this", "is", "a", "list", "of", "strings");


List<String> sorted = strings.stream()
                              .sorted((s1, s2) -> s1.compareTo(s2))
                              .collect(Collectors.toList());

List<String> sorted = strings.stream()
                              .sorted(String::compareTo)
                              .collect(Collectors.toList());

方法引用及其等效的Lambda表达式
Stream接口定义的sorted方法传入Comparator<T>作为参数,
单一抽象方法为int compare(String other)。 sorted方法将每队字符串提供给比较器,并根据返回整数的符号对它们进行排序

使用方法引用在String上调用length方法

Stream.of("this", "is", "a", "stream", "of", "strings")
.map(String::length) // 程序调用length方法每个字符串转换为一个整数,然后打印所有结果。
.forEach(System.out::println)

  • 通过类名访问实例方法
  • 通过对象应用访问实例方法
    方法引用本质上属于Lambda表达式的一种简化语法。

构造函数引用

将方法引用作为流的流水线(stream pipeline)的一部分,以实例化某个对象。
eg: 将一份人员列表 转换为 人员姓名列表

List<String> names = people.stream()
                            .map(per -> per.getName())
                            .collect(Collectors.toList());
// Another method
List<String> names = people.stream()
                            .map(Person::getName())
                            .collect(Collectors.toList());


package com.huida.app.java8.unit01;

import lombok.Data;

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

/**
 * @author wangzhuangzhuang
 * @DESC:
 * @date 2022-02-01 23:13
 */

@Data
class Person{

	private String name;

	public Person(){}

	// 复制构造函数(copy constructor) 传入一个Person参数,并返回一个具有相同特性的新Person
	// 如果需要将流代码从原始实例中分离传来,复制构造函数将非常有用。
	// eg: 有一个人员列表,=》转换为流 =》 再转换为列表 =》那么引用不会发生变化
	public Person(Person p){
		this.name = p.name;
	}

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

	public String getName() {
		return name;
	}

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

}
public class DemoTest02 {
	public static void main(String[] args) {
		// ================================================================================================================
		// 将字符串转换为Person实例
		List<String> names = Arrays.asList("Grace Hopper", "Barbara Liskov", "Ada LoveLace", "Karen Spark Jones");

		List<Person> people = names.stream()
				.map(name -> new Person(name)) // .map(Person::new)
				.collect(Collectors.toList());

		// [Person(name=Grace Hopper), Person(name=Barbara Liskov), Person(name=Ada LoveLace), Person(name=Karen Spark Jones)]
		System.out.println(people);

		// ===============================================================================================================
		// 将列表转换为流,再转换回列表
		Person before = new Person("Grace Hopper");
		List<Person> peoplePlus = Stream.of(before)
										.collect(Collectors.toList());

		Person after = peoplePlus.get(0);

		System.out.println("before == after: " + (before == after));

		before.setName("Grace Murray Hopper");
		System.out.println("after's name: " + after.getName());

		// 使用复制构造函数
		// ===============================================================================================================
		List<Person> peoplePlus001 = Stream.of(before)
											.map(Person::new) // 通过复制构造函数来切断两者之间的连接
											.collect(Collectors.toList());
		after = peoplePlus001.get(0);
		System.out.println("after == before: " + (before == after)); // after == before: false
		System.out.println("before's name: "+ before.getName());
		System.out.println("after's name: " + after.getName());
	}
}

函数式接口

Java8 引入的函数式接口是一种包含单一抽象方法的接口,可以作为Lambda表达式或方法引用的目标

posted @ 2022-02-04 16:02  Felix_Openmind  阅读(74)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}