【问题标题】:How to wrap a java.lang.Appendable into a java.io.Writer?如何将 java.lang.Appendable 包装到 java.io.Writer 中?
【发布时间】:2014-01-18 05:30:16
【问题描述】:

UPDATE2:我自己的适配器类版本,仅在构造函数中调用instanceof,并在flush()close() 函数中使用(Java 1.5)增量(避免之后需要任何反射或逻辑对象构造),包含在这篇文章的底部。 UPDATE1:Marc Baumbach 写了一个简单的适配器,正是我需要的。包括在下面。原始问题如下。


需要java.lang.Appendable 的函数可以接受java.io.Writer,因为Writer 实现了Appendable

反过来呢?我正在使用一个需要编写器的函数,并且我正在尝试创建另一个调用它的函数,该函数接受一个可附加对象并将其传递给原始编写器函数。

我看到您可以扩展抽象的Writer,并将所有write(...) 函数重定向到它们对应的append(...)-s。但是您还必须实现flush()close(),我很清楚如何干净地编写它们,以便这个包装类可以接受任何 Appendable。

我很惊讶没有任何东西可以解决这个问题,无论是在网络上、stackoverflow 上还是在现有的库中。至少我找不到。

我很感激这里的一些指导。谢谢。


回答这个问题的适配器代码。由 Marc Baumbach 撰写(我自己的版本如下):

import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;

public class AppendableWriterAdapter extends Writer {

      private Appendable appendable;

      public AppendableWriterAdapter(Appendable appendable) {
            this.appendable = appendable;
      }

      @Override
      public void write(char[] cbuf, int off, int len) throws IOException {
            appendable.append(String.valueOf(cbuf), off, len);
      }

      @Override
      public void flush() throws IOException {
            if (appendable instanceof Flushable) {
                  ((Flushable) appendable).flush();
            }
      }

      @Override
      public void close() throws IOException {
            flush();
            if (appendable instanceof Closeable) {
                  ((Closeable) appendable).close();
            }
      }

}

这是我自己的版本,基于 Marc,仅在构造函数中使用 instanceof,在 flush()close() 中使用 (Java 1.5) delta。这是为了避免在对象构造之后必须使用任何逻辑或反射。这也发布为gist:https://gist.github.com/aliteralmind/8494917

这个类包含一个演示,然后是两个无操作的增量(一个Flushable,一个Closeable),主函数(newWriterForAppendable(apbl)),然后是适配器类本身。

   import  java.io.Closeable;
   import  java.io.Flushable;
   import  java.io.IOException;
   import  java.io.Writer;
/**
   <P>{@code java NewWriterForAppendable}.</P>
 **/
public class NewWriterForAppendable  {
   /**
      <P>Demonstrates {@code newWriterForAppendable(apbl)} for creating a new {@code Writer} that wraps around {@code System.out} (writes to the console).</P>
    **/
   public static final void main(String[] igno_red)  {
      try  {
         NewWriterForAppendable.newWriterForAppendable(System.out).write("hello");
      }  catch(IOException iox)  {
         throw  new RuntimeException("WriterForAppendableXmpl", iox);
      }
   }
   /**
      <P>A {@code Flushable} whose {@code flush()} function does nothing. This is used by {@link #newWriterForAppendable(Appendable ap_bl) newWriterForAppendable}{@code (apbl)} as a (Java 1.5) delta.</P>

      @see  #newWriterForAppendable(Appendable) newWriterForAppendable(apbl)
    **/
   public static final Flushable FLUSHABLE_DO_NOTHING = new Flushable()  {
      public void flush()  {
      }
   };
   /**
      <P>A {@code Closeable} whose {@code close()} function does nothing. This is used by {@link #newWriterForAppendable(Appendable ap_bl) newWriterForAppendable}{@code (apbl)} as a (Java 1.5) delta.</P>

      @see  #newWriterForAppendable(Appendable) newWriterForAppendable(apbl)
    **/
   public static final Closeable CLOSEABLE_DO_NOTHING = new Closeable()  {
      public void close()  {
      }
   };
   /**
      <P>Creates a new {@code java.io.Writer} that wraps around a {@code java.lang.Appendable}. It properly {@link java.io.Writer#flush() flush}es and {@link java.io.Writer#close() close}s appendables that happened to also be {@link java.io.Flushable}s and/or {@link java.io.Closeable Closeable}s. This uses {@code instanceof} only in the constructor, and a delta in {@code flush()} and {@code close()}, which avoids having to use any logic or reflection after object construction.</P>

      <P>This function is released as a <A HREF="https://gist.github.com/aliteralmind/8494917">gist</A>, and is an example of the <A HREF="http://en.wikipedia.org/wiki/Adapter_pattern#Object_Adapter_pattern">Object Adapter pattern</A>. Thanks to <A HREF="http://stackoverflow.com/users/1211906/marc-baumbach">Marc Baumbach</A> on <A HREF="http://stackoverflow.com">{@code stackoverflow}</A> for the assistance. See (viewed 1/18/2014)
      <BR> &nbsp; &nbsp; <CODE><A HREF="http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer">http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer</A></CODE></P>

      @return  A new writer that uses an appendable to do its output.
      @see  #FLUSHABLE_DO_NOTHING
      @see  #CLOSEABLE_DO_NOTHING
    **/
   public static final Writer newWriterForAppendable(Appendable ap_bl)  {
      return  (new WFA(ap_bl));
   }
   private NewWriterForAppendable()  {
      throw  new IllegalStateException("constructor: Do not instantiate.");
   }
}
class WFA extends Writer  {
   private final Appendable apbl;
   private final Flushable  flbl;
   private final Closeable  clbl;
   public WFA(Appendable ap_bl)  {
      if(ap_bl == null)  {
         throw  new NullPointerException("ap_bl");
      }
      apbl = ap_bl;

      //Avoids instanceof at every call to flush() and close()
      flbl = (Flushable)((ap_bl instanceof Flushable) ? ap_bl
         :  NewWriterForAppendable.FLUSHABLE_DO_NOTHING);
      clbl = (Closeable)((ap_bl instanceof Closeable) ? ap_bl
         :  NewWriterForAppendable.CLOSEABLE_DO_NOTHING);
   }
   @Override
   public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException {
      apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX);
   }
   @Override
   public Writer append(char c_c) throws IOException {
      apbl.append(c_c);
      return  this;
   }
   @Override
   public Writer append(CharSequence c_q) throws IOException {
      apbl.append(c_q);
      return  this;
   }
   @Override
   public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException  {
      apbl.append(c_q, i_ndexStart, i_ndexEndX);
      return  this;
   }
   @Override
   public void flush() throws IOException {
      flbl.flush();
   }
   @Override
   public void close() throws IOException {
      flush();
      clbl.close();
   }

}

【问题讨论】:

  • Nitpick:对于 write(char[], int, int) 的 impl,使用 apbl.append(String.valueOf(a_c, i_ndexStart, i_ndexEndX)); 而不是 apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX); 更有效?我认为这将减少在 start 和 end 不是 0a_c.length 的情况下复制的字节数。
  • 使用CharBuffer.wrap(cbuf, off, len) 而不是String.valueOf(cbuf, off, len) 会更有效,因为这会为现有的cbuf 创建一个视图,并且根本不复制任何内容来创建CharSequence。跨度>

标签: java io writer


【解决方案1】:

通常在Writer 中,flush()close() 用于清除可能尚未提交或发送到流的任何其他写入。通过简单地将所有write 方法直接重定向到Appendable 中的append 方法,您不必担心flush()close(),除非您的Appendable 实现Closeable 和/或@ 987654334@.

一个很好的例子是BufferedWriter。当您为此调用write() 时,它可能不会立即将所有字节发送到最终输出/流。直到您flush()close() 才可能发送某些字节。为了绝对安全,我会在相应的方法中测试被包装的Appendable 是否为CloseableFlushable,然后将其强制转换并执行操作。

这是一个非常标准的设计模式,称为Adapter pattern

这可能是这个适配器的一个很好的实现:http://pastebin.com/GcsxqQxj

【讨论】:

  • 所以您只需将所有writes 重定向到appends,并创建空的closeflush 函数,就这样!?如果这是正确的,那就是没什么。非常感谢!
  • 为了绝对安全,在您的closeflush 中,您可以测试Appendable 是否是CloseableFlusheable,将其转换并执行适当的操作。
  • 啊。所以似乎毕竟需要一些反思。再次感谢。
  • 我已经编辑包含一个应该可以工作的实现的 pastebin。
  • 我已经创建了我自己的适配器类版本,它避免了在对象构造之后必须使用任何逻辑或反射。它已添加到我原帖的底部。
【解决方案2】:

您可以接受任何Appendable,然后检查它是否是Writerinstanceof。然后进行向下转换并调用仅接受 Writer 的函数。

示例:

public void myMethod(Appendable app) throws InvalidAppendableException {

   if (app instanceof Writer) {
      someObj.thatMethod((Writer) app);
   } else {
      throw new InvalidAppendableException();
   }
}

【讨论】:

  • 在某些情况下这是个好主意。但是,我会选择使用非反射版本。
  • 事实证明至少需要一些反思,所以这并没有我想象的那么遥远!
【解决方案3】:

Google 的 Guava 有一个简单的实用程序可以做到这一点:CharStreams.asWriter

实现不是最快的(see),如果你想要最好的性能,你可能想看看 spf4j Streams.asWriter

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多