标签: default-method

在Java 8中扩展List <T>

我经常想将一个列表映射到另一个列表.例如,如果我有一个人员列表,我想要一个他们的名字列表,我想这样做:

目标

List<Person> people = ... ;

List<String> names = people.map(x -> x.getName());
Run Code Online (Sandbox Code Playgroud)

使用Java 8可以实现这样的功能:

JAVA 8版

List<String> names = people.stream()
                           .map(x -> x.getName())
                           .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

但这显然不是那么好.事实上,我认为使用番石榴更清洁:

GUAVA版本

List<String> names = Lists.transform(people, x -> x.getName());
Run Code Online (Sandbox Code Playgroud)

但是,我喜欢链接.那么,我的目标是否可行?

我听说有人说Java 8默认方法类似于C#扩展方法.使用C#扩展方法,我可以轻松地将辅助方法添加到IEnumerable<T>:

public static IEnumerable<TRet> Map<T, TRet>(this IEnumerable<T> list, Func<T, TRet> selector)
{
    return list.Select(selector);
}
Run Code Online (Sandbox Code Playgroud)

但是,我无法弄清楚如何使用默认方法来扩展现有接口.

此外,这显然是一个微不足道的例子.通常,我希望能够扩展List<T>Iterable<T>接口,以便更容易地与流api进行交互.

java lambda guava java-8 default-method

11
推荐指数
1
解决办法
2074
查看次数

JDiagram旧版本在ExtendedArrayList.sort中使用JRE 8抛出StackOverflowError

我正在使用JDiagram JAR,如下所示

Diagram myDigram = new Diagram();
    myDigram.routeAllLinks();
Run Code Online (Sandbox Code Playgroud)

使用JRE 7运行时此代码可以正常工作,但是当它与JRE 8一起运行时,会抛出以下错误:

java.lang.StackOverflowError
    at java.util.Collections.sort(Unknown Source)
    at com.mindfusion.common.ExtendedArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at com.mindfusion.common.ExtendedArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at com.mindfusion.common.ExtendedArrayList.sort(Unknown Source)
Run Code Online (Sandbox Code Playgroud)

我跟着堆栈跟踪到JDiagram反编译代码.观察到routeAllLinks()在另一个对象(比如路由器)上调用RouteLinks(),并且在另一个级别深度调用错误堆栈跟踪中出现的ExtendedArrayList.sort().JDiagram中的"ExtendedArrayList"扩展了ArrayList,并包含一个名为"sort()"的方法,该方法具有以下定义.

  public void sort(Comparator<? super T> paramComparator)
  {
    Collections.sort(this, paramComparator);
  }
Run Code Online (Sandbox Code Playgroud)

在Google上,我发现JRE 8引入了List.sort()并将Collections.sort()调用委托给集合(在我的情况下为ExtendedArrayList)排序方法.因此,库ExtendedArrayList.sort()成为了一个覆盖.它会创建一个无限递归,从而导致stackoverflow.我现在可以用一小段代码重现这个问题.

  • 我们创建JDiagram对象的原始类在运行时由我们产品中的其他组件加载.我们对程序的加载几乎没有控制权.
  • 我们发现最新版本的JDiagram通过用sortJ7()方法替换sort()来解决这个问题.但是,此时我们无法升级库.JDiagram是一个许可的API.
  • ExtendedArrayList由JDiagram在内部实例化,因此我们无法从代码中更改它.

我们尝试过以下目前无效的解决方案

  • Java代理:因为我们的代码不直接调用ExtendedArrayList而且'Diagram'没有任何接口.
  • Spring AOP:我们没有使用spring,我们的程序也被其他组件加载运行时.
  • AspectJ:到目前为止,这显然是一个解决方案.但是,它也没有用,因为我们无法在运行时编写程序.不确定是否有人可以使它工作.

如果有任何要点需要详细说明,请告诉我.欢迎任何帮助.谢谢.

更新 到目前为止,javassist是最好的方法,但JDiagram混淆是阻止解决方案正常工作.我们有点认为考虑到我们的发布日期是不可能的(不得不说).我们已经开始升级库的过程.同时从我们的应用程序中删除了一个由routeAllLinks()方法提供的小功能.. :-(感谢大家的帮助.我将继续研究这个问题,因为我发现它真的很有趣和挑战..我如果我能解决它,我会更新帖子.而且我将继续为@gontard提供他的javassist方法,因为我正在继续我的研究.谢谢.

java collections arraylist java-8 default-method

11
推荐指数
1
解决办法
440
查看次数

为什么Java 8中的Cloneable中没有默认的clone()

Cloneable在Java中本质上是破碎的.具体来说,我对界面的最大问题是它需要一种不定义方法本身的方法行为.因此,如果遍历Cloneable列表,则必须使用反射来访问其定义的行为.但是,在Java 8中,我们现在有默认方法,现在我问为什么没有默认clone()方法Cloneable.

我理解为什么接口不能默认Object方法,但是,这是一个明确的设计决策,因此可以做出异常.

我有点想到弃用Object.clone()并将其内部代码更改为:

if(this instanceof Cloneable) {
    return ((Cloneable) this).clone();
}
else {
    throw new CloneNotSupportedException();
}
Run Code Online (Sandbox Code Playgroud)

并继续前进任何魔法使其clone()成为默认方法Cloneable.这并没有真正解决,clone()仍然可以很容易地错误地实现,但这本身就是另一个讨论.

据我所知,这种变化将完全向后兼容:

  1. 当前覆盖clone()但未实现的类Cloneable(为什么?!)在技术上仍然可以(即使在功能上不可能,但这与以前没有什么不同).
  2. 当前覆盖clone()但实现的类Cloneable在其实现上仍将起相同的作用.
  3. 当前没有覆盖clone(),但确实实现Cloneable(为什么?!)的类现在将遵循规范,即使它在功能上并不完全正确.
  4. 使用反射并提到的那些Object.clone()仍然可以在功能上工作.
  5. super.clone()即使它正在引用,它在功能上仍然是相同的Object.clone().

更不用说这将解决一个巨大的问题Cloneable.虽然繁琐且仍然容易错误地实现,但它将解决界面的巨大面向对象问题.

我能看到的唯一问题是那些实现Cloneable没有义务覆盖的问题clone(),但这与以前没有什么不同.

这已在内部进行过讨论,但从未取得成果吗?如果是这样,为什么?如果是因为接口不能默认使用Object方法,那么在这种情况下做出异常是否有意义,因为所有继承Cloneable的对象都是期待clone()的?

java clone cloneable java-8 default-method

11
推荐指数
2
解决办法
7372
查看次数

可串行标记接口是否包含默认方法?

我认为它不能,因为标记接口原则是没有任何方法,但由于默认方法不是抽象的我不确定.

java interface marker-interfaces java-8 default-method

10
推荐指数
4
解决办法
1168
查看次数

使用不同Java版本的Strange Default Method行为

假设我有以下类层次结构:

interface Collection<E>
{
    Collection<E> $plus(E element)
}

interface MutableCollection<E> extends Collection<E>
{
    @Override
    MutableCollection<E> $plus(E element)
}

interface Set<E> extends Collection<E>
{
    @Override
    Set<E> $plus(E element)
}

interface MutableSet<E> extends Set<E>, MutableCollection<E>
{
    @Override
    default MutableSet<E> $plus(E element)
    {
        // ... implementation
    }
}

abstract class AbstractArraySet<E> implements Set<E>
{
    // ... no $plus(...) implementation
}

class ArraySet<E> extends AbstractArraySet<E> implements MutableSet<E>
{
    // ... no $plus(...) implementation
}
Run Code Online (Sandbox Code Playgroud)

如您所见,只有MutableSet该类提供了该$plus方法的实现.在测试用例中,我在类型的实例上调用此方法ArraySet.测试总是在CI环境中传递,而它总是AbstractMethodError在我的本地环境中失败.在这两种情况下,我都在使用Gradle(2.7).


错误: …

java interface abstract-methods java-bridge-method default-method

10
推荐指数
1
解决办法
293
查看次数

Java默认接口方法具体用例

Java 9即将推出,更多功能将添加到Java接口,如私有方法.default接口中的方法是在Java 8中添加的,主要是为了支持在集合中使用lambda,而不会破坏与该语言的早期版本的复古兼容性.

在Scala中,traits中的方法非常有用.但是,Scala使用不同的方法处理traits而不是Java default.考虑多重继承解决方案或使用traits作为mixin.

除了以上使用,哪些是使用default方法的真实场景值得?这几年是否出现了一些使用它们的模式?使用这种方法可以解决哪些问题?

design-patterns interface java-8 default-method java-9

10
推荐指数
3
解决办法
2614
查看次数

我们应该在接口(Java 8)中对默认方法进行单元测试吗?

我对Java 8中引入的接口中的默认方法实现感到有些困惑.我想知道是否应该专门为接口及其实现的方法编写JUnit测试.我试着谷歌,但我找不到一些指导方针.请指教.

junit unit-testing java-8 default-method

9
推荐指数
1
解决办法
4700
查看次数

继承,组合和默认方法

通常承认,通过继承扩展接口的实现不是最佳实践,并且该组合(例如,从头开始再次实现接口)更加可维护.

这是有效的,因为接口契约迫使用户实现所有所需的功能.但是在java 8中,默认方法提供了一些可以"手动"覆盖的默认行为.请考虑以下示例:我想设计一个用户数据库,该数据库必须具有List的功能.出于效率目的,我选择通过ArrayList来支持它.

public class UserDatabase extends ArrayList<User>{}
Run Code Online (Sandbox Code Playgroud)

这通常不被认为是一种很好的做法,如果真的希望列表的全部功能并遵循通常的"遗产构成"的座右铭,我宁愿这样做:

public class UserDatabase implements List<User>{
  //implementation here, using an ArrayList type field, or decorator pattern, etc.
}
Run Code Online (Sandbox Code Playgroud)

但是,如果不注意,则不需要覆盖某些方法,例如spliterator(),因为它们是List接口的默认方法.问题是,List的spliterator()方法执行得比ArrayList的spliterator()方法差得多,后者已针对ArrayList的特定结构进行了优化.

这迫使开发者

  1. 请注意,ArrayList有自己的,更有效的spliterator()实现,并手动覆盖他自己的List实现的spliterator()方法或
  2. 使用默认方法会失去大量性能.

所以问题是:在这种情况下,人们应该更喜欢构成而不是继承吗?

java inheritance composition java-8 default-method

9
推荐指数
1
解决办法
607
查看次数

为什么接口默认方法?

学习java 8的默认方法.这个链接 就像互联网上的任何其他资源一样

在"最严格的意义上",默认方法是向后退一步,因为它们允许您使用代码"污染"您的接口.但它们提供了最优雅和实用的方式来允许向后兼容.它使Oracle更容易更新所有Collections类,并让您更新Lambda的现有代码.

我的理解是java 8 dev/designer在接口中提供了默认方法,因此所有实现类都不必不必要地覆盖相同的行为,因此提供向后兼容性.例如: - 如果ForEach方法不是默认方法,则实现类的每个集合都必须实现它.同意.

为了克服这个问题,我们可以让一个类提供这些默认方法的实现,然后实现类似arraylist等类可以扩展它.通过这种方式,我们可以对java基础知识(即可重用性和抽象性)进行统计,即保持界面污染较少

我相信java 8开发/设计师已经考虑过这一点,因为他们学到的东西更多,我在这里缺少一些东西.有人可以在这里帮助我们开发人员也可以作为这一重大变化吗?

java java-8 default-method

9
推荐指数
2
解决办法
3232
查看次数

抽象超类的默认接口方法

可以说我有以下结构:

abstract class A {
     abstract boolean foo();
}

interface B {
     default boolean foo() { return doBlah(); }
}

class C extends A implements B {
    //function foo
}
Run Code Online (Sandbox Code Playgroud)

Java现在会抱怨该类C必须实现抽象方法foo A.通过重新定义函数C并简单地调用,我可以相对容易地解决这个问题B.super.foo();.

但是我不明白为什么接口的默认函数B不能单独满足这个要求,我希望能更好地理解java的底层机制.

java java-8 default-method

9
推荐指数
2
解决办法
657
查看次数