Java基础29(Java 8 特性 Java8中Interface接口 Lambda 表达式 Stream流)

2024-06-07 07:04

本文主要是介绍Java基础29(Java 8 特性 Java8中Interface接口 Lambda 表达式 Stream流),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、 Java8中Interface接口

 二、Lambda 表达式

1. lambda的精简写法

2. 函数式接口 Functional Interface

3. 内置函数式接口(Built-in Functional Interfaces)

3.1 Supplier 供给型接口

3.2 Consumer 消费型接口

3.3 Function 函数型接口,r>

3.4 Predicate 断言型接口 ,r>

三、Stream流

1. 创建Stream

2. foreach方法

2. Filter 过滤

3. limit(long )--获取流中的前n个元素

4. skip()--跳过前几个元素 

5. Map 映射

6. Sorted 排序

7. Match 匹配

8. distinct去掉重复的元素9

9. Collectors

Collectors.mapping()将Stream中的元素,映射后,收集至新集合

Collectors.groupingBy() 分组

10. Parallel Streams 并行流

函数式接口总结


一、Java8中Interface接口

interface接口 的设计目的是面向接口编程,提高扩展性。
●Java8中,接口中除了抽象方法外,还可以定义default默认方法和static静态方法。
○default修饰的默认方法,属于实例方法,可以被实现类调用或重写。

  • 调用:实现类必须implements接口,才能调用该接口的default默认方法。
  • 重写:实现类implements不同接口时,接口中存在相同签名的方法(名称、参数、类型完全一致),则实现类必须重写该方法,明确方法定义;

○static修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用interface接口名称调用。

 二、Lambda 表达式

  • Lambda 表达式本质是一个匿名函数,用于把函数作为参数,传入方法中,实现函数式编程风格。
  • 使用Lambda 表达式可以使代码变的更加简洁紧凑。

语法格式
 

(parameters)-> expression 或 (parameters)->{ statements;}接口名 对象名=(参数类型 参数名称)->{方法体}
(参数类型,参数名称): 抽象方法的参数,形参
->固定写法
{}存放方法的内容
public static void main(String[] args) {new Thread(new Runnable() {// 1.定义了一个没有名字的内部类// 2.实现了Runnable接口// 3.创建Runnable实现类对象@Overridepublic void run() {System.out.println("子线程1执行任务");}}).start();new Thread(() -> System.out.println("子线程2执行任务")).start();System.out.println("主线程执行任务");}运行结果:
子线程1执行任务
主线程执行任务
子线程2执行任务

创建函数式接口类型的对象
函数式接口:接口中只有一个抽象方法(static default,抽象方法只能有1个)

//创建函数式接口类型的对象
//函数式接口:接口中只有一个抽象方法(static default,抽象方法只能有1个)//接口名 对象名=(参数类型 参数名称)->{方法体}
//(参数类型,参数名称): 抽象方法的参数,形参
//->固定写法
//{}存放方法的内容//lambda的精简写法
//a.参数的类型省略
//b.()可以省略,参数个数只有1个的时候可以省略
//c.{ return ;}可以省略,只有一条语句的时候才能省略
public class Demo02 {public static void main(String[] args) {goSWimining(new Swimable() {@Overridepublic void swimming() {System.out.println("zkt在游泳");}});//接口名对象名=(参数类型参数名称)->{方法体}goSWimining(() -> {System.out.println("zkt1在游泳");});goSWimining(() -> System.out.println("zkt2在游泳"));}public static void goSWimining(Swimable s) {s.swimming();}
}interface Swimable {void swimming();
}

1. lambda的精简写法

  • 参数的类型省略
  • ()可以省略,参数个数只有1个的时候可以省略
  • { return ;}可以省略,只有一条语句的时候才能省略
public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>(Arrays.asList(3,2,1,5,6,7));//写法1:匿名内部类写Compartor实现类对象
//		Collections.sort(list,new Comparator<Integer>() {
//
//			@Override
//			public int compare(Integer o1, Integer o2) {
//				// TODO Auto-generated method stub
//				return o2-o1;
//			}
//		});//写法2:1ambda表达式写法Collections.sort(list,(Integer o1,Integer o2)->{return o2-o1;});//写法3:省略参数类型Collections.sort(list,( o1, o2)->{return o2-o1;});//写法4:省略{return ;}Collections.sort(list,( o1, o2)->o2-o1);System.out.println(list);}
public class Demo04 {public static void main(String[] args) {List<Person> persons = new ArrayList<Person>();persons.add(new Person("zkt1", 21,177));persons.add(new Person("zkt2", 17,180));persons.add(new Person("zkt3", 24,187));Collections.sort(persons,(p1,p2)->{return p1.getAge()-p2.getAge();});persons.forEach((t)->{System.out.println(t);});}
}class Person {private String name;private int age;private int height;public Person(String name, int age, int height) {super();this.name = name;this.age = age;this.height = height;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + ", height=" + height + "]";}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;}}


2. 函数式接口 Functional Interface

只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用@FunctionalInterface接口定义,强化语义规范。
函数式接口,也被称为SAM 接口(Single Abstract Method Interfaces)

作用
基于函数式接口,可以使用Lambda表达式进行实现,实现函数式编程。

//lambda表达式使用的前提:
//1.方法的参数或者变量的类型是接口
//2.这个接口中只能有一个抽象方法
public class Demo05 {public static void main(String[] args) {test(new Flyable() {@Overridepublic void fly() {System.out.println("我能飞");}});test(() -> {System.out.println("我能飞");});}public static void test(Flyable fly) {fly.fly();}
}
@FunctionalInterface //函数式接口注解,表示此接口只有一个
interface Flyable {public abstract void fly();}
public class Demo01 {public static void main(String[] args) {//调用函数式接口中的方法method((arr) -> {int sum = 0;for (int i : arr) {sum = sum + i;}return sum;});}//使用自定义的函数式接口作为方法的参数public static void method(Opertor op) {int[] arr = { 1, 2, 3, 4 };int sum = op.getSum(arr);System.out.println(sum);}
}@FunctionalInterface
interface Opertor {int getSum(int[] arr);
}

3. 内置函数式接口(Built-in Functional Interfaces)

在 Java 8 中专门有一个包放函数式接口java.util.function,该包下的所有接口都有 @FunctionalInterface 注解,提供函数式编程方式。

3.1 Supplier<T> 供给型接口

抽象方法描述
T get()返回一个自定义数据( 无参数,有返回值)
public class Demo02Supplier {public static void main(String[] args) {// Supplier --- 供给型接口// T get();--方法没有参数,有返回值,需要对外提供一个符合泛型类型的对象数据System.out.println("main中的方法");printMax(()->{System.out.println("Supplier对象的get方法");int[] arr = {1,3,5,10,4};Arrays.sort(arr);return arr[arr.length-1];});}//输出数组中最大的元素public static void printMax(Supplier<Integer> sup) {System.out.println("printMax方法");int max = sup.get();System.out.println(max);}}运行结果:
main中的方法
printMax方法
Supplier对象的get方法
10
public class Demo03Supplier2 {public static void main(String[] args) {// Supplier --- 供给型接口// T get();// 1-100之间的随机数//getRandNum(() -> (int) (Math.random() * 100 + 1));// 20-100随机的数--偶数 Supplier<Integer> sup = () -> {while(true) {int random = (int) (Math.random() * 80 + 20);if((random & 1) == 0) {return random;}}};getRandNum(sup);}public static void getRandNum(Supplier<Integer> sup) {Integer integer = sup.get();System.out.println(integer);}}

3.2 Consumer<T> 消费型接口

抽象方法描述
void accept(T t)接收一个参数进行消费,无返回结果 (因为没有返回值,接口里面执行内容和调用方没什么关联 – 解耦

public class Demo04ConSumer {public static void main(String[] args) {// ConSumer消费型接口 void accept(T t);// 方法有参数,没有返回值,消费一个数据,数据类型由泛型决定//字符串转大写Consumer<String> con1 = s -> System.out.println(s.toUpperCase());//printUpper(con1, "HelloWorld");//字符串转小写Consumer<String> con2 = s -> System.out.println(s.toLowerCase());//printLower(con2, "HelloWorld");printUpeerAndLower(con1,con2,"hxjxky");}public static void printUpper(Consumer<String> con, String str) {con.accept(str);}public static void printLower(Consumer<String> con, String str) {con.accept(str);}public static void printUpeerAndLower(Consumer<String> con1,Consumer<String> con2, String str) {
//		con1.accept(str);
//		con2.accept(str);//使用默认方法andThen()//在消费一个数据的时候,可以先做一个操作,然后再做一个操作,实现操作组合con1.andThen(con2).accept(str);}}
运行结果:
HXJXKY
hxjxky

3.3 Function<T,R> 函数型接口

Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen)。
抽象方法描述
R apply(T t)传入一个参数,返回需要的结果
public class Demo05Function {
//	    interface Function<T, R> ---转换接口
//	    R apply(T t);public static void main(String[] args) {//将字符串数字转成数字//Function<String, Integer> fun =(str)->{return Integer.parseInt(str);};//简写方式Function<String, Integer> fun =str-> Integer.parseInt(str);method(fun,"12345");//打印字符串的长度method(str-> str.length(), "aabmdijej");}public static void method(Function<String,Integer> f,String str) {Integer num = f.apply(str);System.out.println(num);}
}
运行结果:
12345
9
public class Demo06Function2 {public static void main(String[] args) {method(str->str.length(),num->new double[num], "abdf");}//将一个字符串转成对应的长度的double类型的数组// string-->Integer// Integer-->double[]public static void method(Function<String, Integer> f1, Function<Integer, double[]> f2, String str) {Integer num = f1.apply(str);double[] d = f2.apply(num);System.out.println(Arrays.toString(d));}}
运行结果:
[0.0, 0.0, 0.0, 0.0]

3.4 Predicate<T,R> 断言型接口 

Predicate接口是只有一个参数的返回布尔类型值的 断言型 接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与and,或or,非negate)
抽象方法描述
boolean test(T t)传入一个参数,返回布尔值(满足:true,不满足:false)
public class Demo07Predicate {// Predicate boolean test(T t)--传入一个参数,返回值为布尔类型的// 根据传入的参数,进行某些判断,结果boolean// 断言型接口public static void main(String[] args) {//判断某个数字是否是偶数//boolean b=method((num)->{return (num&1)==0;},102);Predicate<Integer> p1=num->(num&1)==0;boolean b=method(p1,102);System.out.println("102是否是偶数:"+b);//判断某个数字是否大于100Predicate<Integer> p2=num->num>=100;boolean b1 =method(p2, 22);System.out.println("22是否是大于100:"+b1);boolean b2 =method(p1,p2,5);System.out.println(b2);}public static boolean method(Predicate<Integer> pre,Integer num) {boolean b=pre.test(num);return b;}public static boolean method(Predicate<Integer> p1,Predicate<Integer> p2,Integer num) {//与运算boolean b=p1.and(p2).test(num);//或运算boolean b1=p1.or(p2).test(num);//非boolean b2=p1.negate().test(num); return b2;}
}运行结果:
102是否是偶数:true
22是否是大于100:false
true

三、Stream流

  • java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
  • Stream操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,可以连续完成多个操作。
public class Demo01 {public static void main(String[] args) {List<String>  list = new ArrayList<String>();Collections.addAll(list,"张三","李四","王五","张kt");//1.拿到所有姓张的元素ArrayList<String> listZhangArrayList = new ArrayList<String>();for (String string : list) {if(string.startsWith("张")) {listZhangArrayList.add(string);}}//2.拿到长度为3的元素ArrayList<String> threeArrayList = new ArrayList<String>();for (String string : listZhangArrayList) {if(string.length() ==3)threeArrayList.add(string);}//3.打印保存for (String string : threeArrayList) {System.out.println(string);}System.out.println("================");list.stream().filter(str->str.startsWith("张")).filter(str->str.length()==3).forEach(str->System.out.println(str));}}

1. 创建Stream

Stream 的创建需要指定一个数据源。

//Stream流的创建方法
public class Demo02 {
//	1.Collection集合提供方法 default Stream<E> steam()
//	2.Stream接口提供ofpublic static void main(String[] args) {
//		1.Collection集合提供方法 default Stream<E> steam()List<String> list = new ArrayList<String>();Stream<String> stream1 = list.stream();System.out.println(stream1);Set<String> set = new HashSet<String>();stream1 = set.stream();System.out.println(stream1);Map<Integer, String> map = new HashMap<Integer, String>();Stream<Integer> strem2 = map.keySet().stream();Stream<String> strem3 = map.values().stream();Stream<Map.Entry<Integer, String>> strem4 = map.entrySet().stream();//方式2:Stream<String> strem5 =Stream.of("aa","bb","cc");String[] strs = {"aa","bb","cc"};Stream<String> strem6 =Stream.of(strs);int[] ints= {1,2,3,4,5};Stream<int[]> strem7 =Stream.of(ints);}}

2. foreach方法

List<String> list = new ArrayList<String>();Collections.addAll(list, "z张三", "l李四", "w王五", "z张kt");// 1.foreach方法--list.stream().forEach(str-> System.out.println(str));System.out.println(list.stream().count());
运行结果:
z张三
l李四
w王五
z张kt
4

2. Filter 过滤

过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作。所以过滤后的结果,可以继续进行其它Stream操作(例如forEach,forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作)。

	List<String> list = new ArrayList<String>();Collections.addAll(list, "张三", "李四", "王五", "z张柯特");// 3.filter()list.stream().filter((str)->str.length()==2).forEach(System.out::println);
运行结果:
张三
李四
王五

3. limit(long )--获取流中的前n个元素

List<String> list = new ArrayList<String>();Collections.addAll(list, "张三", "李四", "王五", "z张柯特");// 4.Stream limit(long )--获取流中的前n个元素list.stream().limit(3).forEach(System.out::println);
运行结果:
张三
李四
王五

4. skip()--跳过前几个元素 

List<String> list = new ArrayList<String>();Collections.addAll(list, "张三", "李四", "王五", "z张柯特");// 5.skip()--跳过前几个元素list.stream().skip(2).forEach(System.out::print);
运行结果:
王五z张柯特

5. Map 映射

映射是一个中间操作, 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。

List<String> list = new ArrayList<String>();Collections.addAll(list, "张三", "李四", "王五", "z张柯特");// 6.map()--可以将一种流转成另一种流list.stream().map((str)->{returnstr.length();}).forEach(System.out::println);
运行结果:
2
2
2
4

6. Sorted 排序

排序是一个 中间操作,返回的是排序好后的 Stream。(不影响原数据)

List<String> list = new ArrayList<String>();Collections.addAll(list, "z张三", "l李四", "w王五", "z张柯特");// 7.sorted() sorted(Compartor)list.stream().sorted((s1,s2)->{returns2.length()-s1.length();}).forEach(System.out::println);
运行结果:
z张柯特
z张三
l李四
w王五

7. Match 匹配

Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是 最终操作 ,并返回一个 boolean 类型的值。

List<String> list = new ArrayList<String>();Collections.addAll(list, "z张三", "l李四", "w王五", "z张柯特");// 8.allMatch()--判断所有的元素是否满足某个条件// anyMatch() noneMatchboolean b=list.stream().allMatch(str->str.length()==3);System.out.println(b);boolean b1=list.stream().anyMatch(str->str.length()==3);System.out.println(b1);boolean b3 = list.stream().noneMatch(str -> str.length() == 4);System.out.println(b3);
运行结果:
false
true
false

8. distinct去掉重复的元素9

public class Demo03 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList("aa","bb","cc"));arrayList.stream().distinct().forEach(System.out::println);ArrayList<Person> persons = new ArrayList<Person>();persons.add(new Person("zkt1"));persons.add(new Person("zkt2"));persons.add(new Person("zkt1"));persons.add(new Person("zkt2"));persons.stream().distinct().forEach(System.out::println);}
}
class Person{private String nameString;public Person(String nameString) {super();this.nameString = nameString;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((nameString == null) ? 0 : nameString.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (nameString == null) {if (other.nameString != null)return false;} else if (!nameString.equals(other.nameString))return false;return true;}@Overridepublic String toString() {return "Person [nameString=" + nameString + "]";}}
运行结果:
aa
bb
cc
Person [nameString=zkt1]
Person [nameString=zkt2]

9. Collectors

public static void main(String[] args) {// ● Collectors.toList()// ● Collectors.toSet()// ● Collectors.toMap()// Collectors.toCollection()List<String> langList = Arrays.asList("abc", "debft", "gkh", "abc");LinkedList<String> newList2 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toCollection(LinkedList::new));List<String> newList1 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toList());Set<String> newset1 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toSet());Map<String, Integer> newmap1 = langList.stream().filter(s -> s.contains("b")).distinct().collect(Collectors.toMap(s -> s, s -> s.length()));System.out.println(newList2);System.out.println(newset1);System.out.println(newmap1);}
运行结果:
[abc, debft, abc]
[abc, debft]
{abc=3, debft=5}

Collectors.mapping()将Stream中的元素,映射后,收集至新集合

public static void main(String[] args) {List<String> numberStrings = Arrays.asList("4344", "6641", "3432", "6432", "6423", "9423");//Collectors.mapping()将Stream中的元素,映射后,收集至新集合//过滤掉不包含字符3的元素,并将其转成Integer类型的集合List<Integer> intList = numberStrings.stream().filter(s -> s.contains("3")).collect(Collectors.mapping(s -> Integer.parseInt(s), Collectors.toList()));for (Integer integer : intList) {System.out.println(integer);}}

Collectors.groupingBy() 分组

public static void main(String[] args) {// Collectors.groupingBy() 分组List<String> langList = Arrays.asList("abc", "de", "gkhf", "abc");// 按照首字符分组Map<Character, List<String>> map = langList.stream().collect(Collectors.groupingBy((s) -> s.charAt(0), Collectors.toList()));System.out.println(map);// 按照长度分组Map<Integer, List<String>> map1 = langList.stream().collect(Collectors.groupingBy((s) -> s.length(), Collectors.toList()));System.out.println(map1);}
运行结果:
{a=[abc, abc], d=[de], g=[gkhf]}
{2=[de], 3=[abc, abc], 4=[gkhf]}

10. Parallel Streams 并行流

Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<Integer>();// 获取并行流的方法1:.parallelStream()Stream<Integer> stream1 = arrayList.parallelStream();// 获取并行流的方法2:stream().parallel()Stream<Integer> stream2 = arrayList.stream().parallel();//检查查并行流testParaller();}// 并行private static void testParaller() {long number=Stream.of(9, 3, 4, 6, 1).parallel().filter(num -> {System.out.println(Thread.currentThread().getName() +"@"+ num);return true;}).count();System.out.println(number);}

函数式接口总结

  • Predicate、Function、Consumer、Comparator
  • 通过链式编程,使得它可以方便地对数据进行链式处理。
  • 方法参数都是函数式接口类型。
  • 一个 Stream 只能操作一次,操作完就关闭了,继续使用这个 Stream 会报错。
  • Stream 不保存数据,不改变数据源。

这篇关于Java基础29(Java 8 特性 Java8中Interface接口 Lambda 表达式 Stream流)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038474

相关文章

Python19 lambda表达式

在 Python 中,lambda 表达式是一个小型匿名函数,通常用于实现简单、单行的函数。lambda 函数可以接受任意数量的参数,但只能有一个表达式。 基本语法: lambda arguments: expression 这里,arguments 是传递给 lambda 的参数,expression 是关于这些参数的表达式,它的计算结果就是 lambda 函数的返回值。 使用

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。