嗨,假设我们有一个包含许多数组列表的类,并包含非常类似的方法,如下所示
public class Foo {
private ArrayList<Rapper> rapperList = new ArrayList<>();
private ArrayList<Musician> musicianList = new ArrayList<>();
private ArrayList<Stadium> stadiumList = new ArrayList<>();
public List<String> getRapperName() {
ArrayList<String> rapperNameList = new ArrayList<>();
for (Rapper r : rapperList) {
rapperNameList.add(r.getRapperName());
}
return rapperNameList;
}
public List<String> getMusicianName() {
ArrayList<String> musicianNameList = new ArrayList<>();
for (Musician m : musicianNameList) {
musicianNameList.add(m.getMusicianName());
}
return musicianNameList;
} //done
public List<String> getStadiumID() {
// exactly the same as above (using same logic)
}
}
我省略了getStadiumID方法代码,因为它与上面的代码非常相似,并且所有方法都遵循相同的逻辑:
我觉得有很多重复的代码,因为我基本上遵循相同的逻辑,并想知道是否有一种方法将这些方法简化为一种。我正在研究java中的泛型,但似乎无法从中获得任何东西。
假设我的知识仅限于Java 7(任何高于7的东西我都不知道lambda等等)
答案 0 :(得分:2)
基本上,你在这里做的是映射列表中的每个元素:
<link href="https://vjs.zencdn.net/6.7/video-js.css" rel="stylesheet"/>
<script src="https://vjs.zencdn.net/6.7/video.js"></script>
<script src="https://cdn.rawgit.com/videojs/videojs-youtube/c4be481f/dist/Youtube.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<video id="my_video" class="video-js vjs-default-skin" controls preload="auto" width="640" height="400">
</video>
<hr>
<button onclick="playVideo(0)">play 0 (mp4)</button>
<button onclick="playVideo(1)">play 1 (mp4)</button>
<button onclick="playVideo(2)">play 2 (youtube)</button>
<hr>
<div id="info"></div>
您可以将此包装在采用return list.stream().map(fn).collect(Collectors.toList());
和List<T> list
的方法中,其中Function<T, S> fn
是列表元素的类型(例如问题代码中的S
)
String
然后您可以调用:
private static <T, S> List<S> makeList(List<T> list, Function<T, S> fn) {
return list.stream().map(fn).collect(Collectors.toList());
}
您可以在Java 8之前的代码中实现这一点;但它不会很漂亮。
首先,您需要一个public List<String> getRapperName() {
return makeList(rapperList, Rapper::getRapperName);
}
public List<String> getMusicianName() {
return makeList(musicianList, Musician::getMusicianName);
}
界面。您可以使用Guava中的一个,其他一些库;或者只是自己定义一个,如果你不想采取依赖:
Function
然后定义interface Function<T, S> {
S apply(T input);
}
方法:
makeList
然后调用:
private static <T, S> List<S> makeList(List<T> list, Function<T, S> fn) {
ArrayList<String> result = new ArrayList<>();
for (T t : list) {
result.add(fn.apply(t));
}
return result;
}
语法多么混乱。
通过将public List<String> getRapperName() {
return makeList(rapperList, new Function<Rapper, String>() {
@Override public String apply(Rapper r) {
return r.getRapperName();
}
});
}
public List<String> getMusicianName() {
return makeList(musicianList, new Function<Musician, String>() {
@Override public String apply(Musician m) {
return m.getMusicianName();
}
});
}
拉出到常量等等,可以使它看起来更清晰;但老实说,你在这里有更多的代码(以及非惯用代码),而不仅仅是复制你当前的代码。
答案 1 :(得分:1)
好的......当然你可以使用泛型,但你可能需要更改一些东西....我将使用Java 7以防万一,但使用Java 8的东西可以变得容易一些。< / p>
首先直接进入要重写的课程:
public class Foo<T extends NamedObject> {
//We will get to what is NamedObject in a moment
private ArrayList<T> list = new ArrayList<>();
public List<String> getNames() {
ArrayList<String> nameList = new ArrayList<>();
for (T r : list) {
nameList.add(r.getName());
}
return nameList;
}
}
现在你应该能够使用这样的类,有一个小的编译错误(为什么?因为我们还没有了解NamedObject应该是什么):
Foo<Rapper> rapperObj = new Foo<>();
rapperObj.getNames();
Foo<Musician > musicianObj = new Foo<>();
musicianObj.getNames();
我们可以定义NamedObject(随意更改适合您的名称)作为定义一个“getName”方法的接口,并使Rapper,Musician和任何拥有名称的类实现此方法。在Rapper课程中使用“rapperName”,在音乐家课程中使用“musicianName”听起来有点多余,在Rapper中只有“名字”应该足以让每个人都像解释者的名字一样解释它(你不觉得)并且让它更容易也适合我们。
public interface NamedObject {
String getName();
}
public class Rapper implements NamedObject {
//Instead of rapperName put only name
@Override
public String getName() { ... }
... //All the things you have in this class
}
没有时间测试它,但这应该可以解决问题。
注意:实际上可能有另一种方法可以在没有接口的情况下解决它,使用Foo作为抽象类,并为每个对象类型设置一个子类
答案 2 :(得分:0)
在Java 8中,我们将使用lambdas。这可以在Java 7中重新编码,如下所示:
public class Foo {
private ArrayList<Rapper> rapperList = new ArrayList<>();
private ArrayList<Musician> musicianList = new ArrayList<>();
private ArrayList<Stadium> stadiumList = new ArrayList<>();
public List<String> getRapperName() {
return asStringList(rapperList, new StringGetter<Rapper>() {
@Override
public String get(Rapper it) {
return it.getRapperName();
}
});
}
public List<String> getMusicianName() {
return asStringList(musicianList, new StringGetter<Musician>() {
@Override
public String get(Musician it) {
return it.getMusicianName();
}
});
}
interface StringGetter <T> {
String get(T it);
}
private <T> List<String> asStringList(List<T> list, StringGetter<T> getter) {
List<String> stringList = new ArrayList<>();
for(T t: list) {
stringList.add(getter.get(t));
}
return stringList;
}
}
答案 3 :(得分:-1)
您还可以将您的类作为可用于处理任何对象的通用类(说唱歌手,音乐家,体育场......)
public class GenericsDemo<T> {
private ArrayList<T> genericList = new ArrayList<>();
public ArrayList<T> getGenericList() {
return genericList;
}
public void setGenericList(ArrayList<T> genericList) {
this.genericList = genericList;
}
public List<String> getGenericName() {
ArrayList<String> genericNameList = new ArrayList<>();
for (T obj : genericList) {
Field field = obj.getClass().getDeclaredField("name");
Object nameValue = field.get(obj);
genericNameList.add(nameValue );
}
return genericNameList;
}
}
从主类中创建此类的对象并将其用于任何类型。
class GenericsMain {
GenericsDemo<Rapper> rapperObj = new GenericsDemo<>();
//create arraylist of any object
//call the setter method
//call the getname method
}