How do I use BufferedReader.lines() method to read file?

The BufferedReader.lines() method is a Java 8 method that returns a Stream, each element of which is a line read from the BufferedReader. This allows you to perform operations on each line with Java’s functional programming methods.

Returning a Stream of strings makes the BufferedReader.lines() method very efficient in terms of memory usage when working with large files. It reads the file line by line, instead of loading the entire file into memory at once.

Here is how it’s used to read from a file:

package org.kodejava.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class BufferedReaderLines {
    public static void main(String[] args) {
        Path path = Paths.get("README.MD");
        try (BufferedReader reader = Files.newBufferedReader(path)) {
            reader.lines().forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

This code opens a BufferedReader on the file located at the given path and uses the lines() method to get a Stream of lines from the file. Each line is then printed to the console using the System.out::println method reference.

The try-with-resources statement is there to ensure that the BufferedReader is closed after we’re done with it, even if an exception was thrown. The catch block is to handle a potential IOException which would be due to a file read error.

Bear in mind that not every situation requires or benefits from using streams, and in some cases, traditional processing methods might be more suitable. But when dealing with large datasets and when you wish to write declarative, clean, and efficient code, this method can be extremely useful.

What is Java Stream API?

The Java Stream API is a powerful tool introduced in Java 8. It is designed to process data in a declarative way. More specifically, it makes it easy to process sequences of data elements, such as collections or arrays.

Here are some key points about Java Stream API:

  1. Non-mutating: Operations on streams do not mutate the source of the stream, rather they produce a new stream that encapsulates the result.
  2. Functional in nature: An important concept in Stream API is that it allows computations on data to be expressed as lambda functions.
  3. Lazy computation: The computation on the source data is only performed when it’s actually needed. This can result in significant performance boosts.
  4. Parallelizable operations: Stream operations can transparently take advantage of multicore architectures, leading to significantly increased performance.

Here’s a simple example of how the Stream API might be used:

import java.util.List;
import java.util.stream.Stream;

public class Stream1 {
    public static void main(String[] args) {
        List<String> collected = Stream.of("Java", "Kotlin", "Scala")
                .filter(lang -> lang.startsWith("J"))
                .map(String::toUpperCase)
                .toList();
    }
}

In this example, we create a stream from a list of strings, filter to keep only those that start with “J”, convert them to uppercase, and then collect them into a new list.

In Java, there are several ways to create Streams. Here are some common methods:

  • From Collection or Arrays: All collections in Java which extends Collection interface can be converted to Stream.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Stream2 {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        Stream<String> myStream = myList.stream();

        String[] myArray = new String[]{"a", "b", "c"};
        Stream<String> myArrayStream = Arrays.stream(myArray);
    }
}
  • Using Stream.of(): You can create a Stream from specific set of object references with Stream.of().
import java.util.stream.Stream;

public class Stream3 {
    public static void main(String[] args) {
        Stream<String> streamOfString = Stream.of("a", "b", "c");
    }
}
  • From File: In the java.nio.file package, you can use Files.lines(), to read a file into a Stream of lines.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class Stream4 {
    public static void main(String[] args) {
        try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • Stream.iterate() and Stream.generate(): These methods let you generate streams in a programmatic way.
import java.util.stream.Stream;

public class Stream5 {
    public static void main(String[] args) {
        Stream<String> stringStream = Stream.generate(() -> "element").limit(10);
        Stream<Integer> integerStream = Stream.iterate(0, n -> n + 1).limit(10);
    }
}

In the above example, Stream.generate() creates a Stream of specified lambda function (always “element” in this case) which can be limited using limit(). Stream.iterate() creates a Stream based on the initial element and a lambda function for subsequent elements.

  • Using Stream.builder(): You can create streams using Stream.builder() where you can add elements in a Stream in a programmatic way.
import java.util.stream.Stream;

public class Stream6 {
    public static void main(String[] args) {
        Stream.Builder<String> myStreamBuilder = Stream.<String>builder().add("a").add("b").add("c");
        Stream<String> stringStream = myStreamBuilder.build();
    }
}

Remember, once a Stream is consumed, it can’t be reused. You have to create a new stream to perform any new computation.

What are Static Methods on interface in Java?

In Java SE 8 and later, you can define static methods on interfaces. A static method is a method associated with the class, not the instance. This means you can call a static method without creating an instance of the class.

This feature can be particularly useful when providing utility methods that act on instances of the interface. You would normally keep these in a separate utility class, but by having these on the interface itself can lead to more readable and maintainable code.

Here is a simple example:

interface MyInterface {
    static void myStaticMethod() {
        System.out.println("Static Method on Interface");
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface.myStaticMethod(); // Call without creating instance
    }
}

In this example, myStaticMethod() is a static method defined on MyInterface. You call it using the interface name (MyInterface.myStaticMethod()), without needing to create an instance of MyInterface.

Keep in mind that static methods in interfaces are not inherited by classes that implement the interface or sub-interfaces, so you always have to use the interface name when calling them.

The Stream interface in Java has several static methods that provide useful functionality for working with sequences of elements, such as collections. Here is an example that uses the Stream.of() static method, which allows you to create a Stream from a set of objects:

import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        Stream.of("Hello", "World", "Interface", "Static", "Methods")
              .map(String::toUpperCase)
              .forEach(System.out::println);
    }
}

In this example, we use Stream.of() to create a Stream from a set of String objects. We then use map() to convert each string in the stream to uppercase, and forEach() to print out each string.

Here is another example, this time using the IntStream.range() static method:

import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        IntStream.range(1, 6)
                 .forEach(System.out::println);
    }
}

In this example, IntStream.range(1, 6) creates a stream of integers from 1 (inclusive) to 6 (exclusive). The forEach() method is then used to print out each integer in the stream.

What is Default Methods in Java?

Default methods are a feature introduced in Java 8, allowing the declaration of methods in interfaces, apart from abstract methods. They are also known as defender methods or virtual extension methods.

With the use of default keyword, these methods are defined within the interface and provide a default implementation. This means they can be directly used by any class implementing this interface without needing to provide an implementation for these methods.

The main advantage of default methods is that they allow the interfaces to be evolved over time without breaking the existing code.

Here’s an example of a default method in an interface:

interface MyInterface {
    void abstractMethod();

    default void defaultMethod() {
        System.out.println("This is a default method in the interface");
    }
}

In the above example, any class implementing MyInterface needs to provide an implementation for abstractMethod(), but not for defaultMethod() unless it needs to override the default implementation.

Before Java 8, we could declare only abstract methods in interfaces. It means that classes which implement the interface were obliged to provide an implementation of all methods declared in an interface. However, this was not flexible for developers, especially when they wanted to add new methods to the interfaces.

For instance, here is an interface used by multiple classes:

interface Animal {
    void eat();
}

Now, if we wanted to add a new method called run(), all classes that implement Animal would need to define this method, which could potentially introduce bugs and is quite cumbersome if we have many classes that implement the interface.

To mitigate such issues, Java 8 introduced default methods in interfaces. With default methods, we can now add new methods in the interface with a default implementation, thereby having the least impact on the classes that implement the interface.

interface Animal {
    void eat();

    default void run() {
        System.out.println("Running");
    }
}

So in the updated Animal interface, the run() method is a default method. Classes implementing Animal can choose to override this method, but they are not obliged to do so. If a class does not provide an implementation for this method, the default implementation from the interface will be used.

Here’s an example implementation of the Animal interface:

class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // Output: Dog is eating
        dog.run();  // Output: Running
    }
}

As you can see, the Dog class didn’t implement the run method, but we’re still able to call dog.run() because of the default implementation in the Animal interface.

Note: In case a class implements multiple interfaces and these interfaces have default methods with identical signatures, the compiler will throw an error. The class must override the method to resolve the conflict.

What is a Functional Interface in Java?

A Functional Interface in Java is an interface that has exactly one abstract method. Apart from this abstract method, it can include default and static methods. Java 8 introduced the @FunctionalInterface annotation to ensure an interface follows the rules of Functional Interface. It’s optional but good practice to use this annotation.

Functional interfaces are extensively used in Java’s lambda expressions. The main purpose of a functional interface is to be used as Lambda Expressions or Method References.

Here’s a basic example of defining a functional interface:

@FunctionalInterface
interface GreetingService {
    void sayMessage(String message);
}

You could use it in conjunction with a lambda like this:

GreetingService greetService = message -> System.out.println("Hello " + message);
greetService.sayMessage("world");

In the code above, message -> System.out.println("Hello " + message) is a lambda expression that provides the implementation of the abstract method sayMessage(String message).

Java 8 has also defined several built-in functional interfaces. These built-in interfaces are packed in the java.util.function package. Some common ones include Predicate<T>, Function<T, R>, Supplier<T>, and Consumer<T>. Furthermore, BinaryOperator<T>, UnaryOperator<T>, BiFunction<T, U, R> are some other standard functional interfaces available.

Here are some examples of Java 8 built-in functional interfaces:

1. Predicate

Predicate<T> is a functional interface that takes a single input and returns a boolean value. It is located in java.util.function package.

Predicate<String> lengthCheck = s -> s.length() > 5;
System.out.println(lengthCheck.test("Hello"));  // Output: false

Predicate is often used when you need to pass some sort of condition or filter as a parameter. For example, you might be checking if the User inputs are valid:

Predicate<String> isValidEmail = email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
System.out.println(isValidEmail.test("[email protected]"));  // Output: true
System.out.println(isValidEmail.test("testgmail.com"));   // Output: false

2. Function

Function<T, R> is an interface that accepts one argument and produces a result.

Function<String, Integer> parse = Integer::parseInt;
System.out.println(parse.apply("123"));  // Output: 123

A Function<T, R> can be useful when you need to convert from one type to another, such as transforming a list of String into a list of Integer.

Function<String, Integer> stringToInteger = Integer::parseInt;
List<String> strings = Arrays.asList("1", "2", "3");
List<Integer> integers = strings.stream()
                                .map(stringToInteger)
                                .collect(Collectors.toList());

3. Consumer

Consumer<T> is an interface that takes one argument and returns no results. It is meant for implementing side effects.

Consumer<String> printer = System.out::println;
printer.accept("Hello");  // Output: Hello

The Consumer<T> interface is often used in conjunction with Java streams or Optional, where you have a collection of objects, and you want to perform a certain action on each of the objects.

Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());
List<String> names = Arrays.asList("Jon", "Sansa", "Arya", "Bran");
names.forEach(printUpperCase);

4. Supplier

Supplier<T> is an interface that does not take any argument, but it produces a result.

Supplier<LocalDate> current = LocalDate::now;
System.out.println(current.get());  // Output: [current date]

Suppose you have a class RandomService that produces random numbers and is supposed to be used by other classes in your system.

class RandomService {
    Supplier<Double> getRandomNumber = Math::random;
}

// Usage in another class
RandomService rs = new RandomService();
System.out.println(rs.getRandomNumber.get());

5. BinaryOperator and UnaryOperator

UnaryOperator<T> takes one argument and returns a result of the same type. BinaryOperator<T> takes two arguments and returns a result of the same type.

UnaryOperator<String> upperifier = String::toUpperCase;
System.out.println(upperifier.apply("hello"));  // Output: HELLO

BinaryOperator<String> concatenator = String::concat;
System.out.println(concatenator.apply("Hello ", "World"));  // Output: Hello World

You have already learned about a few key functional interfaces in Java and how to use them with lambda expressions. Now, I’ll introduce you to a few more advanced topics about functional interfaces:

1. Custom Functional Interface

If the built-in functional interfaces in Java do not satisfy your requirements, you can define your own functional interfaces. Here is an example of a custom functional interface:

@FunctionalInterface
interface CustomInterface {
    String concatenateStrings(String s1, String s2);
}

You can now use it like this:

CustomInterface ci = (s1, s2) -> s1 + s2;
System.out.println(ci.concatenateStrings("Hello", " World")); // Output: Hello World

2. Method References

In some cases, lambdas just call an existing method. In those cases, we can use method references to make the code clearer. Here are some examples

Consumer<String> printer = System.out::println; // same as s -> System.out.println(s)

Predicate<String> lengthCheck = String::isEmpty; // same as s -> s.isEmpty()

Supplier<LocalDate> current = LocalDate::now; // same as () -> LocalDate.now()

3. Chaining Functional Interface Calls (Compose and AndThen)

You can chain multiple calls of Function, Consumer, and Predicate using default methods they provide, such as compose, andThen.

Function<Integer, Integer> multiplyBy2 = x -> x * 2;
Function<Integer, Integer> add1 = x -> x + 1;
Function<Integer, Integer> add1AndThenMultiplyBy2 = add1.andThen(multiplyBy2);

System.out.println(add1AndThenMultiplyBy2.apply(2)); // Output: 6

Remember that with compose, functions execute in reverse order.

Function<Integer, Integer> multiplyBy2ThenAdd1 = add1.compose(multiplyBy2);

System.out.println(multiplyBy2ThenAdd1.apply(2)); // Output: 5

Chaining calls this way leads to functional-style programming that can make your code more readable and maintainable by creating pipelines of transformations.

Real-world use of the functional interface is prevalent in Java library features such as Stream API, where they come together with lambda expressions to offer functional programming capabilities. They help contribute to writing clean, robust and concurrent code structures.

Overall, functional interfaces bring the power of functional programming to Java and are extensively used for implementing simple callback-style interfaces, or for defining “thin” data structures used in control statements, among other uses.

How do I read a file line by line using Java NIO?

The java.nio.file.Files.lines() method is a Java NIO method used to read the contents of a file line by line. The code snippet will read the file from the specified filePath and print each line to the console. The Files.lines() method returns a Stream of strings, and we use Stream’s forEach method to print each line.

Note that we are using a try-with-resources statement which will automatically close the stream after we are done with it, it’s a good practice to always close streams to free-up system resources.

Here’s a basic example of how you can use it.

package org.kodejava.io;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.stream.Stream;

public class ReadFile {
    public static void main(String[] args) {
        // replace with your file path
        String filePath = "/Users/wayan/lipsum.txt";

        // read file into stream, try-with-resources
        try (Stream<String> stream = Files.lines(Paths.get(filePath))) {

            stream.map(String::trim)
                    .forEach(System.out::println);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The Files.lines() method, along with other Java I/O and NIO methods, provide several important benefits and features:

  1. Memory Efficiency: This method reads the file line by line lazily, which means it doesn’t load the entire content of the file into memory. This is particularly useful when dealing with large files that could potentially exhaust system memory.
  2. Stream API Integration: The method returns a Stream<String>, it can naturally integrate with Java Stream API. This allows you to take advantage of powerful functions provided by Stream API such as filtering, mapping, reduction, etc., to process the file data effectively.
  3. Readability: Using Files.lines() with a try-with-resources construct results in more compact and readable code compared to older methods such as BufferedReader. The try-with-resources statement ensures that each resource is closed at the end of the statement, which can simplify cleanup code and avoid resource leaks.
  4. Exceptions Handling: I/O operations can generally throw IOException which are checked Exceptions in Java. Using Files.lines() within a try-with-resources statement ensures that any underlying resources are closed properly, even in the event of an Exception.
  5. Parallel Processing: Since Files.lines() method returns a Stream<String>, you can convert this stream into a parallel stream if you want to process the file with multithreading.

Remember, like with many programming choices, whether to use Files.lines() or another method depends on the specific needs and constraints of your project.

What are Method References in Java?

Method references in Java are a feature that was introduced in Java 8. They provide a way to refer to a method without actually executing it. They are often used in conjunction with Java’s functional programming features, such as Streams and Lambdas, where a method to be executed is often expected as a parameter.

The syntax for a method reference is the name of the class (or the name of an object), followed by :: and the method’s name. Here’s an example:

List<String> words = Arrays.asList("Hello", "Method", "References", "In", "Java");

// Let's use a method reference to print each word in the list
words.forEach(System.out::println);

In the above code, System.out::println is a method reference. The forEach method expects a lambda that takes a parameter and does something with it. Here, the println method of the System.out class is being referenced, and it will be used to print each word in the list.

There are four types of method references in Java:

  1. Static method reference: They refer to the static methods of a class. For example, ClassName::staticMethodName.
  2. Instance method reference of a particular object: They refer to the instance methods of a particular object. For example, in above code System.out::println.
  3. Instance method reference of an arbitrary object: They refer to the instance methods where the first parameter is the target of the method. For example, String::length.
  4. Constructor reference: They refer to the constructor of a class. For example, ClassName::new.

Let’s take a deeper look at the four kinds of method references with more elaborated examples.

1. Static method references:

Static method references can be used when the method to be invoked is a static method. For example:

package org.kodejava.basic;

import java.util.stream.Stream;

public class StaticMethodRef {
    public static void main(String[] args) {
        String[] array = {"Java", "Python", "Ruby", "JavaScript"};
        Stream.of(array).forEach(StaticMethodRef::printStr);
    }

    static void printStr(String str) {
        System.out.println("printStr method called with value: " + str);
    }
}

In this example, the printStr method is a static method, and we reference this method using StaticMethodRef::printStr.

2. Instance method reference of a particular object:

Instance method references can be used when the method to be invoked is an instance method. For example:

package org.kodejava.basic;

import java.util.stream.Stream;

public class InstanceMethodRef {
    public static void main(String[] args) {
        InstanceMethodRef instance = new InstanceMethodRef();
        String[] array = {"Java", "Python", "Ruby", "JavaScript"};
        Stream.of(array).forEach(instance::printInstanceStr);
    }

    void printInstanceStr(String str) {
        System.out.println("printInstanceStr method called with value: " + str);
    }
}

In this example, printInstanceStr is an instance method, and we create an instance of InstanceMethodRef and refer to an instance method instance::printInstanceStr.

3. Instance method reference of an arbitrary object:

We can do this when we have a collection of instances and want to invoke a method on them. For example:

package org.kodejava.basic;

import java.util.stream.Stream;

public class InstanceMethodReferenceArbitrary {
    public static void main(String[] args) {
        String[] array = {"Java", "Python", "Ruby", "JavaScript"};
        Stream.of(array).map(String::toUpperCase).forEach(System.out::println);
    }
}

In this example, String::toUpperCase invokes the toUpperCase method for every instance of the String in the Stream.

4. Constructor reference:

Constructor references are used for a constructor call. For example:

package org.kodejava.basic;

import java.util.stream.Stream;

class Student {
    String name;

    Student(String name) {
        this.name = name;
    }
}

public class ConstructorReference {
    public static void main(String[] args) {
        Stream.of("John", "Martin", "Don")
                .map(Student::new)
                .forEach(student -> System.out.println("Student name is: " + student.name));
    }
}

In the above example, Student::new creates a new instance of Student.

How do I sort strings based on their length?

You can sort strings based on their length using the sort method combined with a custom comparator. In the code snippet below we are going to use the Arrays.sort() method. We pass an array of string to the sort() method and also a lambda expression as the custom comparator.

Here is how you’d do it in Java:

package org.kodejava.util;

import java.util.Arrays;

public class SortStringsExample {
    public static void main(String[] args) {
        String[] strings = {"Hello", "World", "Java", "is", "beautiful"};

        // Sort the array based on string length
        Arrays.sort(strings, (a, b) -> a.length() - b.length());

        // Print the sorted array
        Arrays.stream(strings).forEach(System.out::println);
    }
}

In this example, an array of strings is sorted in increasing order of their lengths. If you want to sort them in descending order, you can change the comparator to (a, b) -> b.length() - a.length().

The output of the code snippet above is:

is
Java
Hello
World
beautiful

How do I convert Base64 string to image file?

In the previous example, How do I convert an image file to a Base64 string?, you’ve seen how to convert image file to base64 string.

In this example, you will see how you can convert a base64 string back into an image file. Below are examples of how to do this in Java, using the Java 8 native java.util.Base64 class.

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;

public class Base64ToImage {
    public static void main(String[] args) throws Exception {
        // this is your Base64 encoded string
        String base64String = "iVBORw0...";

        byte[] decodedBytes = Base64.getDecoder().decode(base64String);
        Files.write(Paths.get("/path/to/your/outputimage.png"), decodedBytes);
    }
}

Just replace “/path/to/your/outputimage.png” with the actual path where you want to save the image.

This code will decode the base64 string back into a byte array, and then it will write this byte array into an image file. Be careful with the format of the image (PNG, JPG, etc.) as the format of the output file should match the format of the original base64-encoded image.

How do I convert an image file to a Base64 string?

A Base64 string is a way of encoding binary data using 64 printable characters, which are the 26 uppercase letters of the English alphabet, the 26 lowercase letters of the English alphabet, the 10 numerical digits, and the “+” and “/” symbols. This makes a total of 64 distinct characters, hence the name “Base64”.

Base64 encoding is commonly used when there is a need to encode binary data, especially when that data needs to be stored and transferred over media that is designed to handle text.

The primary use case of this encoding is to allow binary data to be represented in a way that looks and acts as plain text. For example, embedded images in HTML (often as data URIs), and storing complex data in XML or JSON.

In Java, you can use the java.util.Base64 classes to convert an image file to a base64 String. You can use it to convert a JPG or a PNG image file, or basically any binary image files. Here is a simple example:

package org.kodejava.util;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;

public class ImageToBase64 {
    public static void main(String[] args) throws Exception {
        String imagePath = "/Users/wayan/tmp/photo-placeholder.png";

        byte[] fileContent = Files.readAllBytes(Paths.get(imagePath));
        String encodedString = Base64.getEncoder().encodeToString(fileContent);

        if (encodedString.length() > 65535) {
            System.out.println("Encoded string is too large");
        } else {
            System.out.println(encodedString);
        }
    }
}

Here are the first 200 characters of the generated base64 string:

iVBORw0KGgoAAAANSUhEUgAAAGQAAAB2CAYAAAA+/DbEAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQA...

The size of a base64-encoded string could be significantly larger than the original file. It’s not always the best way to handle large files or in cases where you’re sensitive to data usage. To check the size of the generated string using the length() method of the String class.

As you can see in the code snippet above, the application will print “Encoded string is too large” if the base64 string of the image is larger than 65535 characters. Otherwise, it will print the base64 string

To use a Base64 encoded string with an HTML <img> tag, you can use the src attribute and specify the data as follows:

<img src="data:image/png;base64,iVBORw0..." alt="Your image description">

In this line:

  • data: is the Data URI scheme specifier.
  • image/png is the media type. This can be image/jpeg, image/gif, or other image types.
  • base64 indicates that the data is base64 encoded.
  • iVBORw0... is where your base64 data begins. Replace iVBORw0... with your base64 string.

You should replace image/png with the actual type of your image and replace the iVBORw0... part with your full Base64 string.

This approach allows you to inline small images directly into your HTML, reducing the number of HTTP requests. However, you should note that if images are large, this can increase the size of your HTML document and slow down load times. It might be more appropriate to use external image files for larger images.

Note that Base64 is not an encryption or hashing method, and should not be used for password or security purposes. It is a binary-to-text encoding schemes that represent binary data in an ASCII string format. It’s designed to be easily transmitted and stored while ensuring that the data remains intact without modification during transport.