code: public static <T> BloomFilter<T> readFrom(InputStream in, Funnel<? super T> funnel)
        throws IOException {
      checkNotNull(in, "InputStream");
      checkNotNull(funnel, "Funnel");
      int strategyOrdinal = -1;
      int numHashFunctions = -1;
      int dataLength = -1;
      try {
        DataInputStream din = new DataInputStream(in);
        // currently this assumes there is no negative ordinal; will have to be updated if we
        // add non-stateless strategies (for which we've reserved negative ordinals; see
        // Strategy.ordinal()).
        strategyOrdinal = din.readByte();
        numHashFunctions = UnsignedBytes.toInt(din.readByte());
        dataLength = din.readInt();
  
        Strategy strategy = BloomFilterStrategies.values()[strategyOrdinal];
        long[] data = new long[dataLength];
        for (int i = 0; i < data.length; i++) {
          data[i] = din.readLong();
        }
        return new BloomFilter<T>(new LockFreeBitArray(data), numHashFunctions, funnel, strategy);
      } catch (RuntimeException e) {
        String message =
            "Unable to deserialize BloomFilter from InputStream."
                + " strategyOrdinal: "
                + strategyOrdinal
                + " numHashFunctions: "
                + numHashFunctions
                + " dataLength: "
                + dataLength;
        throw new IOException(message, e);
      }
    }
docs: Reads a byte stream, which was written by {@linkplain #writeTo(OutputStream)}, into a {@code
  BloomFilter}.
  
  <p>The {@code Funnel} to be used is not encoded in the stream, so it must be provided here.
  <b>Warning:</b> the funnel provided <b>must</b> behave identically to the one used to populate
  the original Bloom filter!
  
  @throws IOException if the InputStream throws an {@code IOException}, or if its data does not
  appear to be a BloomFilter serialized using the {@linkplain #writeTo(OutputStream)} method.