日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java 如何優雅的拷貝對象屬性

瀏覽:20日期:2022-08-20 18:52:01

場景

在 Java 項目中,經常遇到需要在對象之間拷貝屬性的問題。然而,除了直接使用 Getter/Stter 方法,我們還有其他的方法么?當然有,例如 Apache Common Lang3 的 BeanUtils,然而 BeanUtils 卻無法完全滿足吾輩的需求,所以吾輩便自己封裝了一個,這里分享出來以供參考。

需要大量復制對象的屬性 對象之間的屬性名可能是不同的 對象之間的屬性類型可能是不同的

目標

簡單易用的 API

copy: 指定需要拷貝的源對象和目標對象 prop: 拷貝指定對象的字段 props: 拷貝指定對象的多個字段 exec: 執行真正的拷貝操作 from: 重新開始添加其他對象的屬性 get: 返回當前的目標對象 config: 配置拷貝的一些策略

思路

定義門面類 BeanCopyUtil 用以暴露出一些 API 定義每個字段的操作類 BeanCopyField,保存對每個字段的操作 定義 BeanCopyConfig,用于配置拷貝屬性的策略 定義 BeanCopyOperator 作為拷貝的真正實現

圖解

Java 如何優雅的拷貝對象屬性

實現

注:反射部分依賴于 joor, JDK1.8 請使用 joor-java-8

定義門面類 BeanCopyUtil 用以暴露出一些 API

/** * java bean 復制操作的工具類 * * @author rxliuli */public class BeanCopyUtil<F, T> { /** * 源對象 */ private final F from; /** * 目標對象 */ private final T to; /** * 拷貝的字段信息列表 */ private final List<BeanCopyField> copyFieldList = new LinkedList<>(); /** * 配置信息 */ private BeanCopyConfig config = new BeanCopyConfig(); private BeanCopyUtil(F from, T to) { this.from = from; this.to = to; } /** * 指定需要拷貝的源對象和目標對象 * * @param from 源對象 * @param to 目標對象 * @param <F> 源對象類型 * @param <T> 目標對象類型 * @return 一個 {@link BeanCopyUtil} 對象 */ public static <F, T> BeanCopyUtil<F, T> copy(F from, T to) { return new BeanCopyUtil<>(from, to); } /** * 拷貝指定對象的字段 * * @param fromField 源對象中的字段名 * @param toField 目標對象中的字段名 * @param converter 將源對象中字段轉換為目標對象字段類型的轉換器 * @return 返回 {@code this} */ public BeanCopyUtil<F, T> prop(String fromField, String toField, Function<? super Object, ? super Object> converter) { copyFieldList.add(new BeanCopyField(fromField, toField, converter)); return this; } /** * 拷貝指定對象的字段 * * @param fromField 源對象中的字段名 * @param toField 目標對象中的字段名 * @return 返回 {@code this} */ public BeanCopyUtil<F, T> prop(String fromField, String toField) { return prop(fromField, toField, null); } /** * 拷貝指定對象的字段 * * @param field 源對象中與目標對象中的字段名 * @param converter 將源對象中字段轉換為目標對象字段類型的轉換器 * @return 返回 {@code this} */ public BeanCopyUtil<F, T> prop(String field, Function<? super Object, ? super Object> converter) { return prop(field, field, converter); } /** * 拷貝指定對象的字段 * * @param field 源對象中與目標對象中的字段名 * @return 返回 {@code this} */ public BeanCopyUtil<F, T> prop(String field) { return prop(field, field, null); } /** * 拷貝指定對象的多個字段 * * @param fields 源對象中與目標對象中的多個字段名 * @return 返回 {@code this} */ public BeanCopyUtil<F, T> props(String... fields) { for (String field : fields) { prop(field); } return this; } /** * 執行真正的拷貝操作 * * @return 返回 {@code this} */ public BeanCopyUtil<F, T> exec() { new BeanCopyOperator<>(from, to, copyFieldList, config).copy(); return this; } /** * 重新開始添加其他對象的屬性 * 用于在執行完 {@link #exec()} 之后還想復制其它對象的屬性 * * @param from 源對象 * @param <R> 源對象類型 * @return 一個新的 {@link BeanCopyUtil} 對象 */ public <R> BeanCopyUtil<R, T> from(R from) { return new BeanCopyUtil<>(from, to); } /** * 返回當前的目標對象 * * @return 當前的目標對象 */ public T get() { return to; } /** * 配置拷貝的一些策略 * * @param config 拷貝配置對象 * @return 返回 {@code this} */ public BeanCopyUtil<F, T> config(BeanCopyConfig config) { this.config = config; return this; }}

定義每個字段的操作類 BeanCopyField,保存對每個字段的操作

/** * 拷貝屬性的每一個字段的選項 * * @author rxliuli */public class BeanCopyField { private String from; private String to; private Function<? super Object, ? super Object> converter; public BeanCopyField() { } public BeanCopyField(String from, String to, Function<? super Object, ? super Object> converter) { this.from = from; this.to = to; this.converter = converter; } public String getFrom() { return from; } public BeanCopyField setFrom(String from) { this.from = from; return this; } public String getTo() { return to; } public BeanCopyField setTo(String to) { this.to = to; return this; } public Function<? super Object, ? super Object> getConverter() { return converter; } public BeanCopyField setConverter(Function<? super Object, ? super Object> converter) { this.converter = converter; return this; }}

定義 BeanCopyConfig,用于配置拷貝屬性的策略

/** * 拷貝屬性的配置 * * @author rxliuli */public class BeanCopyConfig { /** * 同名的字段自動復制 */ private boolean same = true; /** * 覆蓋同名的字段 */ private boolean override = true; /** * 忽略 {@code null} 的源對象屬性 */ private boolean ignoreNull = true; /** * 嘗試進行自動轉換 */ private boolean converter = true; public BeanCopyConfig() { } public BeanCopyConfig(boolean same, boolean override, boolean ignoreNull, boolean converter) { this.same = same; this.override = override; this.ignoreNull = ignoreNull; this.converter = converter; } public boolean isSame() { return same; } public BeanCopyConfig setSame(boolean same) { this.same = same; return this; } public boolean isOverride() { return override; } public BeanCopyConfig setOverride(boolean override) { this.override = override; return this; } public boolean isIgnoreNull() { return ignoreNull; } public BeanCopyConfig setIgnoreNull(boolean ignoreNull) { this.ignoreNull = ignoreNull; return this; } public boolean isConverter() { return converter; } public BeanCopyConfig setConverter(boolean converter) { this.converter = converter; return this; }}

定義 BeanCopyOperator 作為拷貝的真正實現

/** * 真正執行 copy 屬性的類 * * @author rxliuli */public class BeanCopyOperator<F, T> { private static final Logger log = LoggerFactory.getLogger(BeanCopyUtil.class); private final F from; private final T to; private final BeanCopyConfig config; private List<BeanCopyField> copyFieldList; public BeanCopyOperator(F from, T to, List<BeanCopyField> copyFieldList, BeanCopyConfig config) { this.from = from; this.to = to; this.copyFieldList = copyFieldList; this.config = config; } public void copy() { //獲取到兩個對象所有的屬性 final Map<String, Reflect> fromFields = Reflect.on(from).fields(); final Reflect to = Reflect.on(this.to); final Map<String, Reflect> toFields = to.fields(); //過濾出所有相同字段名的字段并進行拷貝 if (config.isSame()) { final Map<ListUtil.ListDiffState, List<String>> different = ListUtil.different(new ArrayList<>(fromFields.keySet()), new ArrayList<>(toFields.keySet())); copyFieldList = Stream.concat(different.get(ListUtil.ListDiffState.common).stream() .map(s -> new BeanCopyField(s, s, null)), copyFieldList.stream()) .collect(Collectors.toList()); } //根據拷貝字段列表進行拷貝 copyFieldList.stream()//忽略空值.filter(beanCopyField -> !config.isIgnoreNull() || fromFields.get(beanCopyField.getFrom()).get() != null)//覆蓋屬性.filter(beanCopyField -> config.isOverride() || toFields.get(beanCopyField.getTo()).get() == null)//如果沒有轉換器,則使用默認的轉換器.peek(beanCopyField -> { if (beanCopyField.getConverter() == null) { beanCopyField.setConverter(Function.identity()); }}).forEach(beanCopyField -> { final String fromField = beanCopyField.getFrom(); final F from = fromFields.get(fromField).get(); final String toField = beanCopyField.getTo(); try { to.set(toField, beanCopyField.getConverter().apply(from)); } catch (ReflectException e) { log.warn('Copy field failed, from {} to {}, exception is {}', fromField, toField, e.getMessage()); }}); }}

使用

使用流程圖

Java 如何優雅的拷貝對象屬性

測試

代碼寫完了,讓我們測試一下!

public class BeanCopyUtilTest { private final Logger log = LoggerFactory.getLogger(getClass()); private Student student; private Teacher teacher; @Before public void before() { student = new Student('琉璃', 10, '女', 4); teacher = new Teacher(); } @Test public void copy() { //簡單的復制(類似于 BeanUtils.copyProperties) BeanCopyUtil.copy(student, teacher).exec(); log.info('teacher: {}', teacher); assertThat(teacher).extracting('age').containsOnlyOnce(student.getAge()); } @Test public void prop() { //不同名字的屬性 BeanCopyUtil.copy(student, teacher).prop('sex', 'sex', sex -> Objects.equals(sex, '男')).prop('realname', 'name').exec(); assertThat(teacher).extracting('name', 'age', 'sex').containsOnlyOnce(student.getRealname(), student.getAge(), false); } @Test public void prop1() { //不存的屬性 assertThat(BeanCopyUtil.copy(student, teacher).prop('sex', 'sex', sex -> Objects.equals(sex, '男')).prop('realname', 'name2').exec().get()).extracting('age', 'sex').containsOnlyOnce(student.getAge(), false); } @Test public void from() { final Teacher lingMeng = new Teacher().setName('靈夢').setAge(17); //測試 from 是否覆蓋 assertThat(BeanCopyUtil.copy(student, teacher).prop('sex', 'sex', sex -> Objects.equals(sex, '男')).prop('realname', 'name').exec().from(lingMeng).exec().get()).extracting('name', 'age', 'sex').containsOnlyOnce(lingMeng.getName(), lingMeng.getAge(), false); } @Test public void get() { //測試 get 是否有效 assertThat(BeanCopyUtil.copy(student, teacher).prop('sex', 'sex', sex -> Objects.equals(sex, '男')).prop('realname', 'name').exec().get()).extracting('name', 'age', 'sex').containsOnlyOnce(student.getRealname(), student.getAge(), false); } @Test public void config() { //不自動復制同名屬性 assertThat(BeanCopyUtil.copy(new Student().setAge(15), new Teacher()).config(new BeanCopyConfig().setSame(false)).exec().get()).extracting('age').containsOnlyNulls(); //不覆蓋不為空的屬性 assertThat(BeanCopyUtil.copy(new Student().setAge(15), new Teacher().setAge(10)).config(new BeanCopyConfig().setOverride(false)).exec().get()).extracting('age').containsOnlyOnce(10); //不忽略源對象不為空的屬性 assertThat(BeanCopyUtil.copy(new Student(), student).config(new BeanCopyConfig().setIgnoreNull(false)).exec().get()).extracting('realname', 'age', 'sex', 'grade').containsOnlyNulls(); } /** * 測試學生類 */ private static class Student { /** * 姓名 */ private String realname; /** * 年齡 */ private Integer age; /** * 性別,男/女 */ private String sex; /** * 年級,1 - 6 */ private Integer grade; public Student() { } public Student(String realname, Integer age, String sex, Integer grade) { this.realname = realname; this.age = age; this.sex = sex; this.grade = grade; } public String getRealname() { return realname; } public Student setRealname(String realname) { this.realname = realname; return this; } public Integer getAge() { return age; } public Student setAge(Integer age) { this.age = age; return this; } public String getSex() { return sex; } public Student setSex(String sex) { this.sex = sex; return this; } public Integer getGrade() { return grade; } public Student setGrade(Integer grade) { this.grade = grade; return this; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } } /** * 測試教師類 */ private static class Teacher { /** * 姓名 */ private String name; /** * 年齡 */ private Integer age; /** * 性別,true 男,false 女 */ private Boolean sex; /** * 職位 */ private String post; public Teacher() { } public Teacher(String name, Integer age, Boolean sex, String post) { this.name = name; this.age = age; this.sex = sex; this.post = post; } public String getName() { return name; } public Teacher setName(String name) { this.name = name; return this; } public Integer getAge() { return age; } public Teacher setAge(Integer age) { this.age = age; return this; } public Boolean getSex() { return sex; } public Teacher setSex(Boolean sex) { this.sex = sex; return this; } public String getPost() { return post; } public Teacher setPost(String post) { this.post = post; return this; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } }}

如果沒有發生什么意外,那么一切將能夠正常運行!

好了,那么關于在 Java 中優雅的拷貝對象屬性就到這里啦

以上就是Java 如何優雅的拷貝對象屬性的詳細內容,更多關于Java 拷貝對象屬性的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩av首页| 婷婷精品进入| 日韩视频在线一区二区三区 | 天堂√中文最新版在线| 国产精品欧美大片| 国产精品久久久久毛片大屁完整版| 日本成人在线不卡视频| 日本亚洲视频在线| 免费高潮视频95在线观看网站| 日韩成人综合| 国产videos久久| 美女视频一区在线观看| 久久精品一区二区三区中文字幕| 国产精品久久久久久久久久白浆| 国产日韩精品视频一区二区三区| 国产伦理一区| 国产乱人伦精品一区| 国产精品**亚洲精品| 亚洲1区在线| 亚洲精一区二区三区| 婷婷精品在线观看| 国产午夜精品一区在线观看| 久久99久久久精品欧美| 国产成人精品一区二区三区视频| bbw在线视频| 伊人久久高清| 一区在线观看| 中文字幕日本一区二区| 久久精品99国产国产精| 精品国产一区二区三区噜噜噜| 91欧美国产| 午夜久久一区| 日本不卡视频在线| 国产精品巨作av| 高清一区二区三区| 免费观看不卡av| 亚洲狼人精品一区二区三区| 亚洲欧美视频一区二区三区| 欧美天堂在线| 国产欧美日韩一区二区三区在线| 国产精品66| 日韩av在线播放网址| 神马日本精品| 亚洲一区亚洲| 国产欧美大片| 欧美精品日日操| 视频在线在亚洲| 麻豆中文一区二区| 最新中文字幕在线播放| 亚洲一区二区三区免费在线观看 | 久久久国产精品网站| 久久精品1区| 日韩一区二区三区免费视频| 高清精品久久| 日韩一区二区免费看| 国产日产精品_国产精品毛片 | 欧美~级网站不卡| 蜜臀精品久久久久久蜜臀| 日本一二区不卡| 亚洲精品网址| 日韩激情精品| 深夜福利视频一区二区| 视频一区二区三区中文字幕| 国产精品一区二区三区四区在线观看| 日韩欧美综合| 日本不卡高清| 日韩精品欧美| 国产美女视频一区二区| 综合日韩av| 热久久久久久| 亚洲一级高清| 久久久久97| 蜜臀久久久久久久| 久久精品电影| 免费亚洲婷婷| 国产精品美女| 捆绑调教美女网站视频一区| 亚洲免费影视| 国产一区二区三区成人欧美日韩在线观看| 亚洲资源在线| 蜜臀国产一区| 日韩不卡在线观看日韩不卡视频| 美女一区网站| 日韩美女精品| 欧美va天堂在线| 国产夫妻在线| 国产精品亚洲一区二区在线观看| 国产精品普通话对白| 日韩国产欧美| 久久久久国产精品一区三寸| 91精品国产自产观看在线 | 久久只有精品| 欧美一区网站| 一区二区三区四区日韩| 在线日韩欧美| 精品一二三区| 国产亚洲高清一区| 日韩精品免费视频人成| 先锋亚洲精品| 黄色亚洲精品| 欧美日韩黑人| 国产综合婷婷| 欧美成人国产| 五月天久久久| 黄色亚洲大片免费在线观看| 香蕉久久精品| 成人精品中文字幕| 韩国三级一区| 日韩精品免费一区二区在线观看| 成人在线免费观看网站| 欧美日韩伊人| 欧美一区二区三区久久精品| 日韩黄色在线观看| 日韩国产91| 日韩精彩视频在线观看| 日本v片在线高清不卡在线观看| 中文字幕日韩亚洲| 日韩精品乱码av一区二区| 亚洲日韩视频| 99国产精品视频免费观看一公开| 蜜桃av在线播放| 亚洲日本三级| 中文字幕系列一区| 国产精品一区二区三区av| 美女尤物久久精品| 丝袜美腿诱惑一区二区三区 | 激情欧美一区二区三区| 日韩欧美一区二区三区免费看| 中文字幕亚洲影视| 亚洲在线观看| 亚洲精品伊人| 亚洲一区日韩| 在线精品亚洲| 免费成人av在线播放| av成人国产| 亚洲制服一区| 蜜臀av国产精品久久久久| 亚洲一级大片| 日本伊人久久| 亚洲一级大片| 国产亚洲高清在线观看| 四虎精品一区二区免费| 91嫩草精品| 你懂的网址国产 欧美| 欧美日韩一区二区国产| 国产高清日韩| 国产伦精品一区二区三区千人斩| 久久99精品久久久久久园产越南 | 日本大胆欧美人术艺术动态| 日韩视频1区| 肉色欧美久久久久久久免费看| 久久电影tv| 国产综合精品| 伊人久久亚洲热| 亚洲aa在线| 欧美久久精品| 老牛影视精品| 欧美专区18| 亚洲精品乱码久久久久久蜜桃麻豆| 涩涩涩久久久成人精品| 久久一区欧美| 人在线成免费视频| 日本精品影院| 免费人成精品欧美精品| 蜜桃视频一区二区| 男女精品网站| 日韩精品第一| 成人一区而且| 欧美日韩精品免费观看视完整| 亚洲不卡av不卡一区二区| 中文字幕av一区二区三区四区| 青草国产精品久久久久久| 成人一区而且| 亚洲精品电影| 国产精东传媒成人av电影| 99精品国产一区二区三区| 亚洲欧美久久久| 国产精东传媒成人av电影| 午夜av一区| 久久精品99久久久| 麻豆精品在线观看| 亚洲精品极品| 国产精品久久久一区二区| 黄色网一区二区| 欧美特黄一级| 欧美日韩精品一区二区三区在线观看| 久久久91麻豆精品国产一区| 亚洲特色特黄| 视频在线观看91| 免费不卡在线视频| 欧美亚洲一区二区三区| 国产精品福利在线观看播放| 不卡在线一区二区| 亚州国产精品| 999国产精品永久免费视频app| 视频一区二区三区入口| 国产精选久久| 亚洲免费一区二区| 在线精品国产亚洲| 国产成人精品一区二区三区免费 |