Lambda 使用反射排序

huangapple go评论79阅读模式
英文:

Lambda sort using Reflection

问题

我正在进行一个需要使用排序的类列表的项目,我有一个Lambda表达式,根据我需要排序的类的类型工作。排序发生在类本身的日期字段上:

Comparator<Class1> comparatorDescending = (exp1, exp2) -> exp2.getDate().compareTo(exp1.getDate());
this.classlist2sort.sort(comparatorDescending);

然而,我有两个,或许更多需要以这种方式排序的类,我决定将Lambda表达式移到父类并使其成为通用的。这需要一些工作,因为现在我需要将我正在处理的类的类型(Class1.class)传递到父类,然后进行通用排序。我尝试使用反射来实现以下内容:

Method m = this.typeParameterClass.getDeclaredMethod("getDate");

Comparator<T> comparatorDescending = (exp1, exp2) -> {
    try {
        return ((Comparable)m.invoke(exp2)).compareTo(m.invoke(exp1));
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
    }
};
this.classlist2sort((Comparator<? super T>) comparatorDescending);

这样做会给我一个错误消息:Unhandled exceptions: java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException,我按照建议的解决方法尝试将表达式用try catch包围起来,如下所示:

Method[] input = this.typeParameterClass.getDeclaredMethods();
Method m = this.typeParameterClass.getDeclaredMethod("getDate");

Comparator<T> comparatorDescending = (exp1, exp2) -> {
    try {
        return ((Comparable)m.invoke(exp2)).compareTo(m.invoke(exp1));
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
    }
};
this.classlist2sort((Comparator<? super T>) comparatorDescending);

不幸的是,这样做会导致一个Cannot resolve method 'compareTo' in 'Object'错误。我现在想知道我正在尝试做的是否可能。感谢任何帮助。

英文:

I'm working on a project that requires the use of sorted Class lists, and I have a lambda expression that worked according to the type of class I needed to be sorted. The sorting occurs on a date field of the class itself:

Comparator&lt;Class1&gt; comparatorDescending = (exp1, exp2) -&gt; exp2.getDate().compareTo(exp1.getDate());
        this.classlist2sort.sort(comparatorDescending);

However I have two, maybe more classes that need to be sorted in this way and I decided to move the lambda expression above to the parent class and make it a generic. This required a bit of work however in that I now need to pass into the parent class the type of class I'm dealing with (Class1.class), condition on that, then sort with generic. I tried the following using Reflection:

Method m = this.typeParameterClass.getDeclaredMethod(&quot;getDate&quot;);

Comparator&lt;T&gt; comparatorDescending = (exp1, exp2) -&gt;
                m.invoke(exp2).compareTo(m.invoke(exp1));
this.classlist2sort((Comparator&lt;? super T&gt;) comparatorDescending);

Doing so gave me an error message: Unhandled exceptions: java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException to which I followed the suggested workaround of surrounding the expression with a try catch in the following manner:

Method[] input = this.typeParameterClass.getDeclaredMethods();
Method m = this.typeParameterClass.getDeclaredMethod(&quot;getDate&quot;);

Comparator&lt;T&gt; comparatorDescending = (exp1, exp2) -&gt; {
            try {
                return m.invoke(exp2).compareTo(m.invoke(exp1));
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
this.classlist2sort((Comparator&lt;? super T&gt;) comparatorDescending);

Unfortunately, doin this resulted in a Cannot resolve method &#39;compareTo&#39; in &#39;Object&#39; error. I am wondering now if what I'm trying to do is possible. Any help is appreciated

答案1

得分: 3

你可以将方法的返回值转换为 Comparable(您需要确保 getDate 方法的返回值与此匹配)。比较器也可以使用 Comparator.comparing 进行简化。

try {
    Method m = this.typeParameterClass.getDeclaredMethod("getDate");
    this.classlist2sort.sort(Comparator.comparing(o -> {
        try {
            return (Comparable) m.invoke(o);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }).reversed());
} catch (NoSuchMethodException e) {
    throw new RuntimeException(e); // or other handling
}
英文:

You can cast the return value of the method to Comparable (you will have to make sure the return value of getDate matches this). The comparator can also be simplified using Comparator.comparing.

try {
	Method m = this.typeParameterClass.getDeclaredMethod(&quot;getDate&quot;);
	this.classlist2sort.sort(Comparator.comparing(o -&gt; {
		try {
			return (Comparable) m.invoke(o);
		} catch (IllegalAccessException | InvocationTargetException e) {
			throw new RuntimeException(e);
		}
	}).reversed());
} catch (NoSuchMethodException e) {
	throw new RuntimeException(e); // or other handling
}

答案2

得分: 0

如果您可以访问Class1Class2等类的源代码,您可以定义一个用于比较器的接口,从而完全避免使用反射。假设如下:

public interface HasDate {
  LocalDate getDate();
}

我知道名称不好,但这个示例足够了。定义比较器以与HasDate一起工作,然后您可以对实现了该接口的元素的列表进行排序。

public class RandomStuff {

  public static void main(String[] args) {
    Comparator<HasDate> dateComparator = (o1, o2) -> o2.getDate().compareTo(o1.getDate());

    List<Class1> list1 = new ArrayList<>();
    list1.add(new Class1(LocalDate.now()));
    list1.add(new Class1(LocalDate.now().plusDays(1)));
    list1.add(new Class1(LocalDate.now().minusDays(1)));
    list1.sort(dateComparator);
    System.out.println(list1);

    List<Class2> list2 = new ArrayList<>();
    list2.add(new Class2(LocalDate.now()));
    list2.add(new Class2(LocalDate.now().plusDays(1)));
    list2.add(new Class2(LocalDate.now().minusDays(1)));
    list2.sort(dateComparator);
    System.out.println(list2);
  }
}

这样,您可以使用dateComparatorlist1list2中的元素进行排序。

英文:

If you have access to the source code of Class1, Class2, etc. you can define an interface to be used for the comparator and avoid reflection altogether. Let's say:

public interface HasDate {

  LocalDate getDate();
}

I know the name is bad, but it will do for an example. Define the comparator to work with HasDate, and you can sort lists, whose elements implement the interface.

public class RandomStuff {

  public static void main(String[] args) {
    Comparator&lt;HasDate&gt; dateComparator = (o1, o2) -&gt; o2.getDate().compareTo(o1.getDate());

    List&lt;Class1&gt; list1 = new ArrayList&lt;&gt;();
    list1.add(new Class1(LocalDate.now()));
    list1.add(new Class1(LocalDate.now().plusDays(1)));
    list1.add(new Class1(LocalDate.now().minusDays(1)));
    list1.sort(dateComparator);
    System.out.println(list1);

    List&lt;Class2&gt; list2 = new ArrayList&lt;&gt;();
    list2.add(new Class2(LocalDate.now()));
    list2.add(new Class2(LocalDate.now().plusDays(1)));
    list2.add(new Class2(LocalDate.now().minusDays(1)));
    list2.sort(dateComparator);
    System.out.println(list2);
  }
}

huangapple
  • 本文由 发表于 2023年7月11日 05:34:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657477.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定