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

相关文章

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1