1. 简介
JDK8是官方发布的一个大版本, 提供了很多新特性功能给开发者使用, 包含语言、编译器、库、工具和JVM
等方面的十多个新特性。 本文将介绍编码过程中常用的一些新特性. JDK8帮助文档
2.lambda表达式
概念:
语法:
注意:
函数式接口:接口中只有一个抽象方法。
(参数一,参数二):抽象方法的参数
->:分隔符
{}:表示抽象方法的实现
代码示例:
public class Test01 {
public static void main(String[] args) {
// 该构造方法需要传递一个线程任务对象。Runnable类型
MyThread mt = new MyThread();
Thread t1 = new Thread(mt);
t1.start();
Runnable mt2 = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
};
Thread t2 = new Thread(mt2);
t2.start();
// 使用Lambda表达式
Runnable mt3 = () -> {
System.out.println("Lambda表达式");
};
Thread t3 = new Thread(mt3);
t3.start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println("自定义任务接口");
}
}
分析:
- Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心
- 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类
- 为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类
- 必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错
- 而实际上,似乎只有方法体才是关键所在。
2.1无参无返回值
代码示例:
public class Test01 {
public static void main(String[] args) {
// 匿名内部类
Swimming s = new Swimming() {
@Override
public void swim() {
System.out.println("使用匿名内部类的方式");
}
};
s.swim();
// lambda表达式
fun(() -> {
System.out.println("使用lambda表达式");
});
}
// 定义fun方法,接受一个Swimming类型的参数
public static void fun(Swimming s) {
s.swim();
}
}
// 函数式接口
@FunctionalInterface
interface Swimming {
public void swim();
}
2.2有参有返回值
代码示例:
public class Test02 {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三", 55, 180));
list.add(new Person("李四", 49, 190));
list.add(new Person("王五", 60, 200));
list.add(new Person("赵六", 21, 210));
// 对集合中的元素进行排序 按照年龄大小
// 传统做法
Comparator<Person> comparator = new Comparator<Person>() {
// int:0表示新加的元素和集合中原来的比对相同
// int:1表示新加的元素和集合中原来的比对不同 02<01
// int:-1表示新加的元素和集合中原来的比对不同 02>01
@Override
public int compare(Person o1, Person o2) {
return o2.getAge() - o1.getAge();
}
};
Collections.sort(list, comparator);
for (Person person : list) {
System.out.println(person);
}
System.out.println("-------------------------------------------------------------------------------");
Comparator<Person> comparator1 = (Person o1, Person o2) -> {
return o1.getAge() - o2.getAge();
};
Collections.sort(list, comparator1);
for (Person person : list) {
System.out.println(person);
}
System.out.println("-------------------------------------------------------------------------------");
// Lambda表达式
Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());
for (Person person : list) {
System.out.println(person);
}
}
}
class Person{
private String name;
private int age;
private int height;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
public Person(String name, int age, int height) {
this.name = name;
this.age = age;
this.height = height;
}
}
2.3详细介绍lambda表达式
- Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
- 左侧:(参数1,参数2…)表示参数列表
- 右侧:{}内部是方法体
- 注意事项
- 形参列表的数据类型会自动推断
- 如果形参列表为空,只需保留()
- 如果形参只有1个,()可以省略,只需要参数的名称即可
- 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句
- Lambda不会生成一个单独的内部类文件
3.函数式接口
- 如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口,可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上
- @Functionalnterface 注解检测接口是否符合函数式接口。
内置函数式接口的由来
public class Test03 {
public static void main(String[] args) {
Operation o = arr -> {
int sum = 0;
for (int n : arr) {
sum += n;
}
System.out.println(sum);
};
fun(o); // 调用 fun 方法并传递 lambda 表达式
}
public static void fun(Operation o) {
int[] arr = {1, 2, 3, 4, 5};
o.getSum(arr);
}
}
@FunctionalInterface
interface Operation {
// 求数组的和
void getSum(int[] arr);
}
分析:
我们知道使用lambda表达式的前提是需要有函数式接口,而lambda使用时不关心接口名、抽象方法名,只关心抽象方法的参数列表和返回值类型。因此为了让我们使用lambda方便,JDK提供了大量常用的函数式接口。
常见的函数式接口
在java.util.funcation保存
3.1Consumer<T>
这个接口表示接受单个输入参数并且不返回任何结果的操作。它通常用于需要对单个参数执行某些操作,但不需要返回值的情况。
void accept(T t);
public class Test {
public static void main(String[] args) {
Consumer<Double> c = t -> {
System.out.println("按摩消费了:" + t + "元");
};
fun01(c,1000.0);
}
public static void fun01(Consumer<Double> consumer,double money){
consumer.accept(money);
}
}
4.2Supplier<T>供给型函数式接口
这个接口代表一个供给型接口,它不接受任何参数,但会返回一个结果。接口定义非常简单,只有一个抽象方法:
T get();
public class Test02 {
public static void main(String[] args) {
Supplier<Integer> supplier = ()-> (int)(Math.random()*100);
fun(supplier);
}
public static void fun(Supplier<Integer> supplier){
Integer num = supplier.get();
System.out.println("内容为:"+num);
}
}
4.3Function<T,R>函数型函数式接口
这个接口表示一个函数,接受一个类型为
T
的参数,并返回一个类型为R
的结果。接口定义如下:
R apply(T t);
public class Test03 {
public static void main(String[] args) {
fun(s -> s.toUpperCase(),"hello");
}
public static void fun(Function<String ,String> function,String msg){
String s = function.apply(msg);
System.out.println(s);
}
}
4.4Predicate<T>
这个接口表示一个接受单个参数并返回布尔值的断言函数。它用于对传入的参数进行判断,并返回一个布尔值结果。
boolean test(T t);
当传入一个参数时,需要对该参数进行判断时,则需要这种函数。
public class Test04 {
public static void main(String[] args) {
fun(s->s.length()>3?true:false,"撒大大大v啊");
}
public static void fun(Predicate<String> predicate,String name){
boolean b = predicate.test(name);
System.out.println("该名称的长度是否长啊"+b);
}
}
5.方法引用
5.1lambda表达式的冗余
public class Test01 {
public static void main(String[] args) {
Consumer<Integer[]> consumer = arr -> {
int sum = 0;
for (Integer integer : arr) {
sum += integer;
}
System.out.println(sum);
};
fun(consumer);
}
public static void fun(Consumer<Integer[]> consumer){
Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
consumer.accept(arr);
}
public static void sum(Integer[] arr){
int sum = 0;
for (Integer integer : arr) {
sum += integer;
}
System.out.println(sum);
}
}
分析:
如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了: ---方法引用
public class Test01 {
public static void main(String[] args) {
Consumer<Integer[]> consumer1 = Test01::sum;
fun(consumer1);
}
public static void fun(Consumer<Integer[]> consumer){
Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
consumer.accept(arr);
}
public static void sum(Integer[] arr){
int sum = 0;
for (Integer integer : arr) {
sum += integer;
}
System.out.println(sum);
}
}
5.2什么是方法引用?
方法引用允许你直接引用现有方法(静态方法、实例方法或构造方法),而不必像 lambda 表达式那样完全重新实现一个功能。它的语法基本上是
::
符号,后跟方法的名称
方法引用的分类
5.3实例方法引用
实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化静态方法引用类无需实例化,直接用类名去调用。
案例:计算一个字符串列表中每个字符串的长度。
public class Test{
public static void main(String[] args) {
List<String> strings = Arrays.asList("hello", "world", "java", "method", "reference");
// 使用实例方法引用,计算字符串长度
Function<String, Integer> stringLength = String::length;
List<Integer> lengths = strings.stream()
.map(stringLength)
.collect(Collectors.toList());
// 输出字符串长度列表
lengths.forEach(System.out::println);
}
}
5.4对象方法引用
案例:将一个字符串列表转换为大写字母。
public class Test01{
public static void main(String[] args) {
List<String> strings = Arrays.asList("hello", "world", "java", "method", "reference");
// 使用对象方法引用,将字符串转换为大写
Function<String, String> toUpperCase = String::toUpperCase;
List<String> upperCaseStrings = strings.stream()
.map(toUpperCase)
.collect(Collectors.toList());
// 输出转换后的字符串列表
upperCaseStrings.forEach(System.out::println);
}
}
5.5构造方法引用
案例:根据名字创建 Person
对象的列表。
public class Test03{
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用构造方法引用创建 Person 对象
Function<String, Person> personConstructor = Person::new;
List<Person> people = names.stream()
.map(personConstructor)
.collect(Collectors.toList());
// 输出 Person 对象列表
people.forEach(System.out::println);
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
}
还有一部分没有写完!晚会补上!
标签:String,void,特性,Person,JDK8,static,println,public From: https://blog.csdn.net/As_Yua/article/details/140217881